From da6dd903e6f4f9c0503a51884861fd358fcfe363 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Fri, 2 Aug 2024 19:57:00 -0400 Subject: [PATCH 01/41] Migrate Ecosystem Information Cluster to use global structs (#34744) * Migrate Ecosystem Information Cluster to use global structs * Restyled by clang-format --------- Co-authored-by: Restyled.io --- .../ecosystem-information-server.cpp | 8 +++++--- .../ecosystem-information-server.h | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp index 26f1c96cd65fa6..4d7f7b8ddf754e 100644 --- a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp +++ b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp @@ -66,9 +66,10 @@ CHIP_ERROR AttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeVa // TODO(#33223) To improve safety we could make GetEncodableLocationDescriptorStruct a private // memeber method where we explicitly delete member method for the parameter that matches // (LocationDescriptorStruct && aLocationDescriptor). -Structs::LocationDescriptorStruct::Type GetEncodableLocationDescriptorStruct(const LocationDescriptorStruct & aLocationDescriptor) +Globals::Structs::LocationDescriptorStruct::Type +GetEncodableLocationDescriptorStruct(const LocationDescriptorStruct & aLocationDescriptor) { - Structs::LocationDescriptorStruct::Type locationDescriptor; + Globals::Structs::LocationDescriptorStruct::Type locationDescriptor; // This would imply data is either not properly validated before being // stored here or corruption has occurred. VerifyOrDie(!aLocationDescriptor.mLocationName.empty()); @@ -199,7 +200,8 @@ EcosystemLocationStruct::Builder & EcosystemLocationStruct::Builder::SetFloorNum return *this; } -EcosystemLocationStruct::Builder & EcosystemLocationStruct::Builder::SetAreaTypeTag(std::optional aAreaTypeTag) +EcosystemLocationStruct::Builder & +EcosystemLocationStruct::Builder::SetAreaTypeTag(std::optional aAreaTypeTag) { VerifyOrDie(!mIsAlreadyBuilt); mLocationDescriptor.mAreaType = aAreaTypeTag; diff --git a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h index f8407861992d3c..58c64262166403 100644 --- a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h +++ b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h @@ -96,7 +96,7 @@ struct LocationDescriptorStruct { std::string mLocationName; std::optional mFloorNumber; - std::optional mAreaType; + std::optional mAreaType; }; // This intentionally mirrors Structs::EcosystemLocationStruct::Type but has ownership @@ -111,7 +111,7 @@ class EcosystemLocationStruct Builder & SetLocationName(std::string aLocationName); Builder & SetFloorNumber(std::optional aFloorNumber); - Builder & SetAreaTypeTag(std::optional aAreaTypeTag); + Builder & SetAreaTypeTag(std::optional aAreaTypeTag); Builder & SetLocationDescriptorLastEdit(uint64_t aLocationDescriptorLastEditEpochUs); // Upon success this object will have moved all ownership of underlying From 6ba96555aeaad66fc1a0156f13275b7052d8ab6a Mon Sep 17 00:00:00 2001 From: Lazar Kovacic Date: Sat, 3 Aug 2024 02:10:01 +0200 Subject: [PATCH 02/41] TV App: Add validation logic for supported clusters and response commands (#34454) * Add validation logic * Restyled by google-java-format * Restyled by clang-format --------- Co-authored-by: Restyled.io --- .../matter/tv/server/utils/ResourceUtils.java | 67 ++++++++++--------- .../java/ContentAppCommandDelegate.cpp | 39 +++++++++++ 2 files changed, 75 insertions(+), 31 deletions(-) diff --git a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/utils/ResourceUtils.java b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/utils/ResourceUtils.java index 1a04c5294d2f30..f0feb70d529677 100644 --- a/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/utils/ResourceUtils.java +++ b/examples/tv-app/android/App/platform-app/src/main/java/com/matter/tv/server/utils/ResourceUtils.java @@ -58,38 +58,43 @@ public Set getSupportedClusters(final Resources resources, fin SupportedCluster cluster = new SupportedCluster(); while (reader.hasNext()) { String name = reader.nextName(); - if (name.equals(KEY_CLUSTER_ID)) { - cluster.clusterIdentifier = reader.nextInt(); - } else if (name.equals(KEY_FEATURE_FLAGS)) { - cluster.features = reader.nextInt(); - } else if (name.equals(KEY_OPTIONAL_COMMANDS)) { - List commands = new ArrayList<>(); - reader.beginArray(); - while (reader.hasNext()) { - commands.add(reader.nextInt()); + try { + if (name.equals(KEY_CLUSTER_ID)) { + cluster.clusterIdentifier = reader.nextInt(); + } else if (name.equals(KEY_FEATURE_FLAGS)) { + cluster.features = reader.nextInt(); + } else if (name.equals(KEY_OPTIONAL_COMMANDS)) { + List commands = new ArrayList<>(); + reader.beginArray(); + while (reader.hasNext()) { + commands.add(reader.nextInt()); + } + reader.endArray(); + int[] commandIds = new int[commands.size()]; + int i = 0; + for (Integer command : commands) { + commandIds[i++] = command; + } + cluster.optionalCommandIdentifiers = commandIds; + } else if (name.equals(KEY_OPTIONAL_ATTRIBUTES)) { + List attributes = new ArrayList<>(); + reader.beginArray(); + while (reader.hasNext()) { + attributes.add(reader.nextInt()); + } + reader.endArray(); + int[] attributeIds = new int[attributes.size()]; + int i = 0; + for (Integer command : attributes) { + attributeIds[i++] = command; + } + cluster.optionalAttributesIdentifiers = attributeIds; + } else { + reader.skipValue(); } - reader.endArray(); - int[] commandIds = new int[commands.size()]; - int i = 0; - for (Integer command : commands) { - commandIds[i++] = command; - } - cluster.optionalCommandIdentifiers = commandIds; - } else if (name.equals(KEY_OPTIONAL_ATTRIBUTES)) { - List attributes = new ArrayList<>(); - reader.beginArray(); - while (reader.hasNext()) { - attributes.add(reader.nextInt()); - } - reader.endArray(); - int[] attributeIds = new int[attributes.size()]; - int i = 0; - for (Integer command : attributes) { - attributeIds[i++] = command; - } - cluster.optionalAttributesIdentifiers = attributeIds; - } else { - reader.skipValue(); + } catch (NumberFormatException | IllegalStateException e) { + Log.e(TAG, "Invalid number format in JSON for key: " + name, e); + reader.skipValue(); // Skip the invalid entry } } supportedClusters.add(cluster); diff --git a/examples/tv-app/android/java/ContentAppCommandDelegate.cpp b/examples/tv-app/android/java/ContentAppCommandDelegate.cpp index 199ec7761be0c8..8d459588a7a8d6 100644 --- a/examples/tv-app/android/java/ContentAppCommandDelegate.cpp +++ b/examples/tv-app/android/java/ContentAppCommandDelegate.cpp @@ -133,6 +133,26 @@ Status ContentAppCommandDelegate::InvokeCommand(EndpointId epId, ClusterId clust JniUtfString respStr(env, resp); ChipLogProgress(Zcl, "ContentAppCommandDelegate::InvokeCommand got response %s", respStr.c_str()); + Json::CharReaderBuilder readerBuilder; + std::string errors; + + std::unique_ptr testReader(readerBuilder.newCharReader()); + + if (!testReader->parse(respStr.c_str(), respStr.c_str() + std::strlen(respStr.c_str()), &value, &errors)) + { + ChipLogError(Zcl, "Failed to parse JSON: %s\n", errors.c_str()); + env->DeleteLocalRef(resp); + return chip::Protocols::InteractionModel::Status::Failure; + } + + // Validate and access JSON data safely + if (!value.isObject()) + { + ChipLogError(Zcl, "Invalid JSON structure: not an object"); + env->DeleteLocalRef(resp); + return chip::Protocols::InteractionModel::Status::Failure; + } + Json::Reader reader; if (!reader.parse(respStr.c_str(), value)) { @@ -166,7 +186,26 @@ void ContentAppCommandDelegate::FormatResponseData(CommandHandlerInterface::Hand { handlerContext.SetCommandHandled(); Json::Reader reader; + + Json::CharReaderBuilder readerBuilder; + std::string errors; + Json::Value value; + std::unique_ptr testReader(readerBuilder.newCharReader()); + + if (!testReader->parse(response, response + std::strlen(response), &value, &errors)) + { + ChipLogError(Zcl, "Failed to parse JSON: %s\n", errors.c_str()); + return; + } + + // Validate and access JSON data safely + if (!value.isObject()) + { + ChipLogError(Zcl, "Invalid JSON structure: not an object"); + return; + } + if (!reader.parse(response, value)) { return; From ae25a08849eaf8ef321946add264eeef0f0ce8f1 Mon Sep 17 00:00:00 2001 From: Tennessee Carmel-Veilleux Date: Sat, 3 Aug 2024 10:38:34 -0400 Subject: [PATCH 03/41] Fix TC-OCC-3.1 and TC-OCC-3.2 runtime errors (#34747) * Fix TC-OCC-3.1 and TC-OCC-3.2 runtime errors - Refactor common code to be clearer in TC-OCC-3.1/3.2 - Fix runtime errors - Move `await_sequence_of_reports` to matter_testing_support.py - Make a helper to write attributes: `write_single_attribute` Fixes #34730 Testing done: - TC-OCC-3.1 and 3.2 no longer break locally (CI integration pending named pipe update in follow-up) - TC_SWTCH still works * Fix lint * restyle * poke styler * restyle --- src/python_testing/TC_OCC_3_1.py | 52 +++--- src/python_testing/TC_OCC_3_2.py | 161 +++++++------------ src/python_testing/TC_SWTCH.py | 48 +----- src/python_testing/matter_testing_support.py | 74 ++++++++- 4 files changed, 168 insertions(+), 167 deletions(-) diff --git a/src/python_testing/TC_OCC_3_1.py b/src/python_testing/TC_OCC_3_1.py index 4380866333f339..3fd082a62bc974 100644 --- a/src/python_testing/TC_OCC_3_1.py +++ b/src/python_testing/TC_OCC_3_1.py @@ -16,11 +16,11 @@ # # === BEGIN CI TEST ARGUMENTS === # test-runner-runs: run1 -# test-runner-run/run1/app: ${TYPE_OF_APP} +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} # test-runner-run/run1/factoryreset: True # test-runner-run/run1/quiet: True # test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json -# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto --endpoint 1 # === END CI TEST ARGUMENTS === # There are CI issues to be followed up for the test cases below that implements manually controlling sensor device for # the occupancy state ON/OFF change. @@ -29,19 +29,29 @@ import logging import time +from typing import Any, Optional import chip.clusters as Clusters -from chip import ChipDeviceCtrl from chip.interaction_model import Status from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts class TC_OCC_3_1(MatterBaseTest): - async def read_occ_attribute_expect_success(self, endpoint, attribute): + async def read_occ_attribute_expect_success(self, attribute): cluster = Clusters.Objects.OccupancySensing + endpoint = self.matter_test_config.endpoint return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attribute) + async def write_hold_time(self, hold_time: Optional[Any]) -> Status: + dev_ctrl = self.default_controller + node_id = self.dut_node_id + endpoint = self.matter_test_config.endpoint + + cluster = Clusters.OccupancySensing + write_result = await dev_ctrl.WriteAttribute(node_id, [(endpoint, cluster.Attributes.HoldTime(hold_time))]) + return write_result[0].Status + def desc_TC_OCC_3_1(self) -> str: return "[TC-OCC-3.1] Primary functionality with server as DUT" @@ -63,39 +73,37 @@ def pics_TC_OCC_3_1(self) -> list[str]: @async_test_body async def test_TC_OCC_3_1(self): - - endpoint = self.user_params.get("endpoint", 1) - node_id = self.matter_test_config.dut_node_ids[0] hold_time = 10 # 10 seconds for occupancy state hold time self.step(1) # commissioning and getting cluster attribute list - attributes = Clusters.OccupancySensing.Attributes - attribute_list = await self.read_occ_attribute_expect_success(endpoint=endpoint, attribute=attributes.AttributeList) + cluster = Clusters.OccupancySensing + attributes = cluster.Attributes + attribute_list = await self.read_occ_attribute_expect_success(attribute=attributes.AttributeList) - self.step(2) - if attributes.HoldTime.attribute_id in attribute_list: - # write 10 as a HoldTime attibute - write_res = await ChipDeviceCtrl.WriteAttribute(node_id, [(endpoint, attributes.HoldTime(hold_time))]) - asserts.assert_equal(write_res[0].status, Status.Success, "Write HoldTime failed") + has_hold_time = attributes.HoldTime.attribute_id in attribute_list + self.step(2) + if has_hold_time: + # write 10 as a HoldTime attribute + await self.write_single_attribute(cluster.Attributes.HoldTime(hold_time)) else: logging.info("No HoldTime attribute supports. Will test only occupancy attribute triggering functionality") self.step(3) # check if Occupancy attribute is 0 - occupancy_dut = await self.read_occ_attribute_expect_success(endpoint=endpoint, attribute=attributes.Occupancy) + occupancy_dut = await self.read_occ_attribute_expect_success(attribute=attributes.Occupancy) # if occupancy is on, then wait until the sensor occupancy state is 0. if occupancy_dut == 1: # Don't trigger occupancy sensor to render occupancy attribute to 0 - if attributes.HoldTime.attribute_id in attribute_list: - time.sleep(hold_time + 2) # add some extra 2 seconds to ensure hold time has passed. + if has_hold_time: + time.sleep(hold_time + 2.0) # add some extra 2 seconds to ensure hold time has passed. else: # a user wait until a sensor specific time to change occupancy attribute to 0. This is the case where the sensor doesn't support HoldTime. self.wait_for_user_input( prompt_msg="Type any letter and press ENTER after the sensor occupancy is detection ready state (occupancy attribute = 0)") # check sensor occupancy state is 0 for the next test step - occupancy_dut = await self.read_occ_attribute_expect_success(endpoint=endpoint, attribute=attributes.Occupancy) + occupancy_dut = await self.read_occ_attribute_expect_success(attribute=attributes.Occupancy) asserts.assert_equal(occupancy_dut, 0, "Occupancy attribute is still 1.") self.step(4) @@ -103,18 +111,18 @@ async def test_TC_OCC_3_1(self): self.wait_for_user_input(prompt_msg="Type any letter and press ENTER after a sensor occupancy is triggered.") # And then check if Occupancy attribute has changed. - occupancy_dut = await self.read_occ_attribute_expect_success(endpoint=endpoint, attribute=attributes.Occupancy) + occupancy_dut = await self.read_occ_attribute_expect_success(attribute=attributes.Occupancy) asserts.assert_equal(occupancy_dut, 1, "Occupancy state is not changed to 1") self.step(5) # check if Occupancy attribute is back to 0 after HoldTime attribute period # Tester should not be triggering the sensor for this test step. - if attributes.HoldTime.attribute_id in attribute_list: + if has_hold_time: # Start a timer based on HoldTime - time.sleep(hold_time+2) # add some extra 2 seconds to ensure hold time has passed. + time.sleep(hold_time + 2.0) # add some extra 2 seconds to ensure hold time has passed. - occupancy_dut = await self.read_occ_attribute_expect_success(endpoint=endpoint, attribute=attributes.Occupancy) + occupancy_dut = await self.read_occ_attribute_expect_success(attribute=attributes.Occupancy) asserts.assert_equal(occupancy_dut, 0, "Occupancy state is not 0 after HoldTime period") else: diff --git a/src/python_testing/TC_OCC_3_2.py b/src/python_testing/TC_OCC_3_2.py index 3624f1044c40e8..7e811362e2e2a4 100644 --- a/src/python_testing/TC_OCC_3_2.py +++ b/src/python_testing/TC_OCC_3_2.py @@ -19,72 +19,31 @@ # # === BEGIN CI TEST ARGUMENTS === # test-runner-runs: run1 -# test-runner-run/run1/app: ${TYPE_OF_APP} +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} # test-runner-run/run1/factoryreset: True # test-runner-run/run1/quiet: True # test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json -# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto --endpoint 1 # === END CI TEST ARGUMENTS === + # TODO: There are CI issues to be followed up for the test cases below that implements manually controlling sensor device for # the occupancy state ON/OFF change. # [TC-OCC-3.1] test procedure step 4 # [TC-OCC-3.2] test precedure step 3a, 3c import logging -import queue -import time -from typing import Any import chip.clusters as Clusters -from chip import ChipDeviceCtrl -from chip.clusters.Attribute import TypedAttributePath -from matter_testing_support import (AttributeValue, ClusterAttributeChangeAccumulator, MatterBaseTest, TestStep, async_test_body, - default_matter_test_main) +from matter_testing_support import (ClusterAttributeChangeAccumulator, MatterBaseTest, TestStep, async_test_body, + await_sequence_of_reports, default_matter_test_main) from mobly import asserts class TC_OCC_3_2(MatterBaseTest): - async def read_occ_attribute_expect_success(self, endpoint, attribute): + async def read_occ_attribute_expect_success(self, attribute): cluster = Clusters.Objects.OccupancySensing - return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attribute) - - def _await_sequence_of_reports(self, report_queue: queue.Queue, endpoint_id: int, attribute: TypedAttributePath, sequence: list[Any], timeout_sec: float): - start_time = time.time() - elapsed = 0.0 - time_remaining = timeout_sec - - sequence_idx = 0 - actual_values = [] - - while time_remaining > 0: - expected_value = sequence[sequence_idx] - logging.info(f"Expecting value {expected_value} for attribute {attribute} on endpoint {endpoint_id}") - try: - item: AttributeValue = report_queue.get(block=True, timeout=time_remaining) - - # Track arrival of all values for the given attribute. - if item.endpoint_id == endpoint_id and item.attribute == attribute: - actual_values.append(item.value) - - if item.value == expected_value: - logging.info(f"Got expected attribute change {sequence_idx+1}/{len(sequence)} for attribute {attribute}") - sequence_idx += 1 - else: - asserts.assert_equal(item.value, expected_value, - msg="Did not get expected attribute value in correct sequence.") - - # We are done waiting when we have accumulated all results. - if sequence_idx == len(sequence): - logging.info("Got all attribute changes, done waiting.") - return - except queue.Empty: - # No error, we update timeouts and keep going - pass - - elapsed = time.time() - start_time - time_remaining = timeout_sec - elapsed - - asserts.fail(f"Did not get full sequence {sequence} in {timeout_sec:.1f} seconds. Got {actual_values} before time-out.") + endpoint_id = self.matter_test_config.endpoint + return await self.read_single_attribute_check_success(endpoint=endpoint_id, cluster=cluster, attribute=attribute) def desc_TC_OCC_3_2(self) -> str: return "[TC-OCC-3.2] Subscription Report Verification with server as DUT" @@ -124,22 +83,32 @@ def pics_TC_OCC_3_2(self) -> list[str]: @async_test_body async def test_TC_OCC_3_2(self): - - endpoint = self.user_params.get("endpoint", 1) endpoint_id = self.matter_test_config.endpoint - node_id = self.matter_test_config.dut_node_ids[0] + node_id = self.dut_node_id + dev_ctrl = self.default_controller + post_prompt_settle_delay_seconds = 10.0 cluster = Clusters.Objects.OccupancySensing - attributes = Clusters.OccupancySensing.Attributes - occupancy_sensor_type_bitmap_dut = await self.read_occ_attribute_expect_success(endpoint=endpoint, attribute=attributes.OccupancySensorTypeBitmap) + attributes = cluster.Attributes self.step(1) - attribute_list = await self.read_occ_attribute_expect_success(endpoint=endpoint, attribute=attributes.AttributeList) + + occupancy_sensor_type_bitmap_dut = await self.read_occ_attribute_expect_success(attribute=attributes.OccupancySensorTypeBitmap) + has_type_pir = ((occupancy_sensor_type_bitmap_dut & cluster.Enums.OccupancySensorTypeEnum.kPir) != 0) or \ + ((occupancy_sensor_type_bitmap_dut & cluster.Enums.OccupancySensorTypeEnum.kPIRAndUltrasonic) != 0) + has_type_ultrasonic = ((occupancy_sensor_type_bitmap_dut & cluster.Enums.OccupancySensorTypeEnum.kUltrasonic) != 0) or \ + ((occupancy_sensor_type_bitmap_dut & cluster.Enums.OccupancySensorTypeEnum.kPIRAndUltrasonic) != 0) + has_type_contact = (occupancy_sensor_type_bitmap_dut & cluster.Enums.OccupancySensorTypeEnum.kPhysicalContact) != 0 + + attribute_list = await self.read_occ_attribute_expect_success(attribute=attributes.AttributeList) + has_pir_timing_attrib = attributes.PIROccupiedToUnoccupiedDelay.attribute_id in attribute_list + has_ultrasonic_timing_attrib = attributes.UltrasonicOccupiedToUnoccupiedDelay.attribute_id in attribute_list + has_contact_timing_attrib = attributes.PhysicalContactOccupiedToUnoccupiedDelay.attribute_id in attribute_list self.step(2) # min interval = 0, and max interval = 30 seconds attrib_listener = ClusterAttributeChangeAccumulator(Clusters.Objects.OccupancySensing) - await attrib_listener.start(ChipDeviceCtrl, node_id, endpoint=endpoint_id) + await attrib_listener.start(dev_ctrl, node_id, endpoint=endpoint_id, min_interval_sec=0, max_interval_sec=30) # TODO - Will add Namepiped to assimilate the manual sensor untrigger here self.step("3a") @@ -147,7 +116,7 @@ async def test_TC_OCC_3_2(self): self.step("3b") if attributes.Occupancy.attribute_id in attribute_list: - initial_dut = await self.read_occ_attribute_expect_success(endpoint=endpoint, attribute=attributes.Occupancy) + initial_dut = await self.read_occ_attribute_expect_success(attribute=attributes.Occupancy) asserts.assert_equal(initial_dut, 0, "Occupancy attribute is still detected state") # TODO - Will add Namepiped to assimilate the manual sensor trigger here @@ -156,8 +125,8 @@ async def test_TC_OCC_3_2(self): prompt_msg="Type any letter and press ENTER after the sensor occupancy is triggered and its occupancy state changed.") self.step("3d") - self._await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.Occupancy, sequence=[ - 0, 1], timeout_sec=post_prompt_settle_delay_seconds) + await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.Occupancy, sequence=[ + 0, 1], timeout_sec=post_prompt_settle_delay_seconds) self.step("4a") if attributes.HoldTime.attribute_id not in attribute_list: @@ -165,83 +134,73 @@ async def test_TC_OCC_3_2(self): self.skip_all_remaining_steps("4b") self.step("4b") - initial_dut = await self.read_occ_attribute_expect_success(endpoint=endpoint, attribute=attributes.HoldTime) + initial_dut = await self.read_occ_attribute_expect_success(attribute=attributes.HoldTime) self.step("4c") - # write a different a HoldTime attibute + # write a different a HoldTime attribute value diff_val = 12 - await ChipDeviceCtrl.WriteAttribute(node_id, [(endpoint, attributes.HoldTime(diff_val))]) + await self.write_single_attribute(attributes.HoldTime(diff_val)) self.step("4d") - self._await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.HoldTime, sequence=[ - initial_dut, diff_val], timeout_sec=post_prompt_settle_delay_seconds) + await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.HoldTime, sequence=[ + initial_dut, diff_val], timeout_sec=post_prompt_settle_delay_seconds) self.step("5a") - if (occupancy_sensor_type_bitmap_dut & Clusters.OccupancySensing.Enums.OccupancySensorTypeEnum.kPir) == 0: - logging.info("No PIR timing attribute supports. Skip this test cases, 5b, 5c, 5d") + if not has_type_pir or not has_pir_timing_attrib: + logging.info("No PIR timing attribute support. Skip this steps 5b, 5c, 5d") self.skip_step("5b") - self.skip_test("5c") + self.skip_step("5c") self.skip_step("5d") else: self.step("5b") - if attributes.PIROccupiedToUnoccupiedDelay.attribute_id in attribute_list: - initial_dut = await self.read_occ_attribute_expect_success(endpoint=endpoint, attribute=attributes.PIROccupiedToUnoccupiedDelay) - - else: - logging.info("No PIROccupiedToUnoccupiedDelay attribute supports. Terminate this test case") + initial_dut = await self.read_occ_attribute_expect_success(attribute=attributes.PIROccupiedToUnoccupiedDelay) self.step("5c") # write the new attribute value diff_val = 11 - await ChipDeviceCtrl.WriteAttribute(node_id, [(endpoint, attributes.PIROccupiedToUnoccupiedDelay(diff_val))]) + await self.write_single_attribute(attributes.PIROccupiedToUnoccupiedDelay(diff_val)) self.step("5d") - self._await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.PIROccupiedToUnoccupiedDelay, sequence=[ - initial_dut, diff_val], timeout_sec=post_prompt_settle_delay_seconds) + await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.PIROccupiedToUnoccupiedDelay, sequence=[ + initial_dut, diff_val], timeout_sec=post_prompt_settle_delay_seconds) self.step("6a") - if (occupancy_sensor_type_bitmap_dut & Clusters.OccupancySensing.Enums.OccupancySensorTypeEnum.kUltrasonic) == 0: - logging.info("No Ultrasonic timing attribute supports. Skip this test cases, 6b, 6c, 6d") + if not has_type_ultrasonic or not has_ultrasonic_timing_attrib: + logging.info("No Ultrasonic timing attribute supports. Skip steps 6b, 6c, 6d") self.skip_step("6b") - self.skip_test("6c") + self.skip_step("6c") self.skip_step("6d") else: self.step("6b") - if attributes.UltrasonicOccupiedToUnoccupiedDelay.attribute_id in attribute_list: - initial_dut = await self.read_occ_attribute_expect_success(endpoint=endpoint, attribute=attributes.UltrasonicOccupiedToUnoccupiedDelay) - - else: - logging.info("No UltrasonicOccupiedToUnoccupiedDelay attribute supports. Skip this test case") + initial_dut = await self.read_occ_attribute_expect_success(attribute=attributes.UltrasonicOccupiedToUnoccupiedDelay) self.step("6c") # write the new attribute value diff_val = 14 - await ChipDeviceCtrl.WriteAttribute(node_id, [(endpoint, attributes.UltrasonicOccupiedToUnoccupiedDelay(diff_val))]) + await self.write_single_attribute(attributes.UltrasonicOccupiedToUnoccupiedDelay(diff_val)) self.step("6d") - self._await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.UltrasonicOccupiedToUnoccupiedDelay, sequence=[ - initial_dut, diff_val], timeout_sec=post_prompt_settle_delay_seconds) + await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.UltrasonicOccupiedToUnoccupiedDelay, sequence=[ + initial_dut, diff_val], timeout_sec=post_prompt_settle_delay_seconds) self.step("7a") - if (occupancy_sensor_type_bitmap_dut & Clusters.OccupancySensing.Enums.OccupancySensorTypeEnum.kPhysicalContact) == 0: + if not has_type_contact or not has_contact_timing_attrib: logging.info("No Physical contact timing attribute supports. Skip this test case") - self.skip_all_remaining_steps("7b") - - self.step("7b") - if attributes.PhysicalContactOccupiedToUnoccupiedDelay.attribute_id in attribute_list: - initial_dut = await self.t_success(endpoint=endpoint, attribute=attributes.PhysicalContactOccupiedToUnoccupiedDelay) - + self.skip_step("7b") + self.skip_step("7c") + self.skip_step("7d") else: - logging.info("No PhysicalContactOccupiedToUnoccupiedDelay attribute supports. Skip this test case") + self.step("7b") + initial_dut = await self.read_occ_attribute_expect_success(attribute=attributes.PhysicalContactOccupiedToUnoccupiedDelay) - self.step("7c") - # write the new attribute value - diff_val = 9 - await ChipDeviceCtrl.WriteAttribute(node_id, [(endpoint, attributes.PhysicalContactOccupiedToUnoccupiedDelay(diff_val))]) + self.step("7c") + # write the new attribute value + diff_val = 9 + await self.write_single_attribute(attributes.PhysicalContactOccupiedToUnoccupiedDelay(diff_val)) - self.step("7d") - self._await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.PhysicalContactOccupiedToUnoccupiedDelay, sequence=[ - initial_dut, diff_val], timeout_sec=post_prompt_settle_delay_seconds) + self.step("7d") + await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.PhysicalContactOccupiedToUnoccupiedDelay, sequence=[ + initial_dut, diff_val], timeout_sec=post_prompt_settle_delay_seconds) if __name__ == "__main__": diff --git a/src/python_testing/TC_SWTCH.py b/src/python_testing/TC_SWTCH.py index 08bf23d91c30d4..e2ef307973003b 100644 --- a/src/python_testing/TC_SWTCH.py +++ b/src/python_testing/TC_SWTCH.py @@ -36,10 +36,10 @@ import chip.clusters as Clusters import test_plan_support from chip.clusters import ClusterObjects as ClusterObjects -from chip.clusters.Attribute import EventReadResult, TypedAttributePath +from chip.clusters.Attribute import EventReadResult from chip.tlv import uint -from matter_testing_support import (AttributeValue, ClusterAttributeChangeAccumulator, EventChangeCallback, MatterBaseTest, - TestStep, default_matter_test_main, has_feature, per_endpoint_test) +from matter_testing_support import (ClusterAttributeChangeAccumulator, EventChangeCallback, MatterBaseTest, TestStep, + await_sequence_of_reports, default_matter_test_main, has_feature, per_endpoint_test) from mobly import asserts logger = logging.getLogger(__name__) @@ -170,44 +170,6 @@ def _ask_for_release(self): else: time.sleep(self.keep_pressed_delay/1000) - def _await_sequence_of_reports(self, report_queue: queue.Queue, endpoint_id: int, attribute: TypedAttributePath, sequence: list[Any], timeout_sec: float): - start_time = time.time() - elapsed = 0.0 - time_remaining = timeout_sec - - sequence_idx = 0 - actual_values = [] - - while time_remaining > 0: - expected_value = sequence[sequence_idx] - logging.info(f"Expecting value {expected_value} for attribute {attribute} on endpoint {endpoint_id}") - try: - item: AttributeValue = report_queue.get(block=True, timeout=time_remaining) - - # Track arrival of all values for the given attribute. - if item.endpoint_id == endpoint_id and item.attribute == attribute: - actual_values.append(item.value) - - if item.value == expected_value: - logging.info(f"Got expected attribute change {sequence_idx+1}/{len(sequence)} for attribute {attribute}") - sequence_idx += 1 - else: - asserts.assert_equal(item.value, expected_value, - msg="Did not get expected attribute value in correct sequence.") - - # We are done waiting when we have accumulated all results. - if sequence_idx == len(sequence): - logging.info("Got all attribute changes, done waiting.") - return - except queue.Empty: - # No error, we update timeouts and keep going - pass - - elapsed = time.time() - start_time - time_remaining = timeout_sec - elapsed - - asserts.fail(f"Did not get full sequence {sequence} in {timeout_sec:.1f} seconds. Got {actual_values} before time-out.") - def _await_sequence_of_events(self, event_queue: queue.Queue, endpoint_id: int, sequence: list[ClusterObjects.ClusterEvent], timeout_sec: float): start_time = time.time() elapsed = 0.0 @@ -511,8 +473,8 @@ async def test_TC_SWTCH_2_4(self): # - TH expects report of CurrentPosition 1, followed by a report of Current Position 0. logging.info( f"Starting to wait for {post_prompt_settle_delay_seconds:.1f} seconds for CurrentPosition to go {switch_pressed_position}, then 0.") - self._await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.CurrentPosition, sequence=[ - switch_pressed_position, 0], timeout_sec=post_prompt_settle_delay_seconds) + await_sequence_of_reports(report_queue=attrib_listener.attribute_queue, endpoint_id=endpoint_id, attribute=cluster.Attributes.CurrentPosition, sequence=[ + switch_pressed_position, 0], timeout_sec=post_prompt_settle_delay_seconds) # - TH expects at least InitialPress with NewPosition = 1 logging.info(f"Starting to wait for {post_prompt_settle_delay_seconds:.1f} seconds for InitialPress event.") diff --git a/src/python_testing/matter_testing_support.py b/src/python_testing/matter_testing_support.py index 273ffe94b5f821..8275b8f0f83326 100644 --- a/src/python_testing/matter_testing_support.py +++ b/src/python_testing/matter_testing_support.py @@ -27,6 +27,7 @@ import random import re import sys +import time import typing import uuid from binascii import hexlify, unhexlify @@ -331,6 +332,58 @@ def wait_for_report(self): asserts.fail("[AttributeChangeCallback] Attribute {expected_attribute} not found in returned report") +def await_sequence_of_reports(report_queue: queue.Queue, endpoint_id: int, attribute: TypedAttributePath, sequence: list[Any], timeout_sec: float): + """Given a queue.Queue hooked-up to an attribute change accumulator, await a given expected sequence of attribute reports. + + Args: + - report_queue: the queue that receives all the reports. + - endpoint_id: endpoint ID to match for reports to check. + - attribute: attribute to match for reports to check. + - sequence: list of attribute values in order that are expected. + - timeout_sec: number of seconds to wait for. + + This will fail current Mobly test with assertion failure if the data is not as expected in order. + + Returns nothing on success so the test can go on. + """ + start_time = time.time() + elapsed = 0.0 + time_remaining = timeout_sec + + sequence_idx = 0 + actual_values = [] + + while time_remaining > 0: + expected_value = sequence[sequence_idx] + logging.info(f"Expecting value {expected_value} for attribute {attribute} on endpoint {endpoint_id}") + try: + item: AttributeValue = report_queue.get(block=True, timeout=time_remaining) + + # Track arrival of all values for the given attribute. + if item.endpoint_id == endpoint_id and item.attribute == attribute: + actual_values.append(item.value) + + if item.value == expected_value: + logging.info(f"Got expected attribute change {sequence_idx+1}/{len(sequence)} for attribute {attribute}") + sequence_idx += 1 + else: + asserts.assert_equal(item.value, expected_value, + msg="Did not get expected attribute value in correct sequence.") + + # We are done waiting when we have accumulated all results. + if sequence_idx == len(sequence): + logging.info("Got all attribute changes, done waiting.") + return + except queue.Empty: + # No error, we update timeouts and keep going + pass + + elapsed = time.time() - start_time + time_remaining = timeout_sec - elapsed + + asserts.fail(f"Did not get full sequence {sequence} in {timeout_sec:.1f} seconds. Got {actual_values} before time-out.") + + @dataclass class AttributeValue: endpoint_id: int @@ -360,7 +413,7 @@ async def start(self, dev_ctrl, node_id: int, endpoint: int, fabric_filtered: bo self._subscription = await dev_ctrl.ReadAttribute( nodeid=node_id, attributes=[(endpoint, self._expected_cluster)], - reportInterval=(min_interval_sec, max_interval_sec), + reportInterval=(int(min_interval_sec), int(max_interval_sec)), fabricFiltered=fabric_filtered, keepSubscriptions=True ) @@ -977,6 +1030,25 @@ async def read_single_attribute_expect_error( return attr_ret + async def write_single_attribute(self, attribute_value: object, endpoint_id: int = None, expect_success: bool = True) -> Status: + """Write a single `attribute_value` on a given `endpoint_id` and assert on failure. + + If `endpoint_id` is None, the default DUT endpoint for the test is selected. + + If `expect_success` is True, a test assertion fails on error status codes + + Status code is returned. + """ + dev_ctrl = self.default_controller + node_id = self.dut_node_id + endpoint = self.matter_test_config.endpoint if endpoint_id is None else endpoint_id + + write_result = await dev_ctrl.WriteAttribute(node_id, [(endpoint, attribute_value)]) + if expect_success: + asserts.assert_equal(write_result[0].Status, Status.Success, + f"Expected write success for write to attribute {attribute_value} on endpoint {endpoint}") + return write_result[0].Status + async def send_single_cmd( self, cmd: Clusters.ClusterObjects.ClusterCommand, dev_ctrl: ChipDeviceCtrl = None, node_id: int = None, endpoint: int = None, From 3331708d64f8d7e9183895749df20d8bc640ef08 Mon Sep 17 00:00:00 2001 From: mkardous-silabs <84793247+mkardous-silabs@users.noreply.github.com> Date: Sat, 3 Aug 2024 23:08:48 -0400 Subject: [PATCH 04/41] [ICD] Add ICDM 3.3 Automation Scripts (#34741) * Add automated script for the ICDM 3.3 test case * Delete manual scripts * Add test to CI run * Restyled by isort * Fix Linter error --------- Co-authored-by: Restyled.io --- .github/workflows/tests.yaml | 1 + .../certification/Test_TC_ICDM_3_3.yaml | 267 ------------ src/app/tests/suites/manualTests.json | 1 - src/python_testing/TC_ICDM_3_3.py | 380 ++++++++++++++++++ 4 files changed, 381 insertions(+), 268 deletions(-) delete mode 100644 src/app/tests/suites/certification/Test_TC_ICDM_3_3.yaml create mode 100644 src/python_testing/TC_ICDM_3_3.py diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index adf04727976032..996b8a6178a57c 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -549,6 +549,7 @@ jobs: scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_5.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ICDM_2_1.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ICDM_3_1.py' + scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ICDM_3_3.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ICDManagementCluster.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_IDM_1_2.py' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_IDM_1_4.py' diff --git a/src/app/tests/suites/certification/Test_TC_ICDM_3_3.yaml b/src/app/tests/suites/certification/Test_TC_ICDM_3_3.yaml deleted file mode 100644 index dcf55057b7b9a9..00000000000000 --- a/src/app/tests/suites/certification/Test_TC_ICDM_3_3.yaml +++ /dev/null @@ -1,267 +0,0 @@ -# Copyright (c) 2024 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. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default - -name: 217.2.4. [TC-ICDM-3.3] Verify UnregisterClient command with DUT as Server - -PICS: - - ICDM.S - - ICDM.S.C00.Rsp - - ICDM.S.C02.Rsp - -config: - nodeId: 0x12344321 - cluster: "Basic Information" - endpoint: 0 - -tests: - - label: "Preconditions" - verification: | - 1.Commission DUT to TH (can be skipped if done in a preceding test). - 2a.TH reads from the DUT the RegisteredClients attribute. - 2b.If list of registered clients is not empty, unregister existing client(s) - 2c.TH reads from the DUT the RegisteredClients attribute. Verify that the DUT response contains empty list of registered clients. - disabled: true - - - label: - "Step 1: TH sends UnregisterClient command with the CheckInNodeID - (CheckInNodeID1)." - PICS: ICDM.S.C02.Rsp - verification: | - ./chip-tool icdmanagement unregister-client 1 1 0 - - [1702437560.584692][2341:2343] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0002 Status=0x8b - [1702437560.584811][2341:2343] CHIP:TOO: Error: IM Error 0x0000058B: General error: 0x8b (NOT_FOUND) - disabled: true - - - label: - "Step 2a: TH sends RegisterClient command. - CheckInNodeID: - registering clients node ID (CheckInNodeID2) - MonitoredSubject: - monitored subject ID (MonitorSubID2) - Key: shared secret between the - client and the ICD (Key2)" - PICS: ICDM.S.C00.Rsp - verification: | - ./chip-tool icdmanagement register-client 2 2 hex:1234567890abcdef1234567890abcdef 1 0 - On TH(chip-tool) verify that DUT responds with status code as success - - [1702437824.926527][2361:2363] CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0001 - [1702437824.926625][2361:2363] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Command 0x0000_0001 - [1702437824.926835][2361:2363] CHIP:TOO: RegisterClientResponse: { - [1702437824.926901][2361:2363] CHIP:TOO: ICDCounter: 2124479668 - [1702437824.926955][2361:2363] CHIP:TOO: } - disabled: true - - - label: "Step 2b: TH reads from the DUT the RegisteredClients attribute." - PICS: ICDM.S.A0003 - verification: | - ./chip-tool icdmanagement read registered-clients 1 0 - - On TH(Chip-tool), Verify that the DUT response contains a list of 1 registered client of given CheckInNodeID, MonitoredSubject, and Key - - [1702437846.906320][2364:2366] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0003 DataVersion: 2633987690 - [1702437846.906504][2364:2366] CHIP:TOO: RegisteredClients: 2 entries - [1702437846.906687][2364:2366] CHIP:TOO: [1]: { - [1702437846.906746][2364:2366] CHIP:TOO: CheckInNodeID: 112233 - [1702437846.906800][2364:2366] CHIP:TOO: MonitoredSubject: 112233 - [1702437846.906880][2364:2366] CHIP:TOO: FabricIndex: 1 - [1702437846.906934][2364:2366] CHIP:TOO: } - [1702437846.907003][2364:2366] CHIP:TOO: [2]: { - [1702437846.907059][2364:2366] CHIP:TOO: CheckInNodeID: 2 - [1702437846.907108][2364:2366] CHIP:TOO: MonitoredSubject: 2 - [1702437846.907160][2364:2366] CHIP:TOO: FabricIndex: 1 - [1702437846.907211][2364:2366] CHIP:TOO: } - disabled: true - - - label: - "Step 3: TH sends UnregisterClient command with the CheckInNodeID - (CheckInNodeID3)." - PICS: ICDM.S.C02.Rsp - verification: | - ./chip-tool icdmanagement unregister-client 3 1 0 - - [1702437560.584692][2341:2343] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0002 Status=0x8b - [1702437560.584811][2341:2343] CHIP:TOO: Error: IM Error 0x0000058B: General error: 0x8b (NOT_FOUND) - disabled: true - - - label: - "Step 4a: Setup the TH such that is has administrator privileges for - the ICDM cluster." - verification: | - chip-tool default has admin privilege - disabled: true - - - label: - "Step 4b: TH sends UnregisterClient command with the CheckInNodeID - (CheckInNodeID2)." - PICS: ICDM.S.C02.Rsp - verification: | - ./chip-tool icdmanagement unregister-client 2 1 0 - - [1702438116.143490][2387:2389] CHIP:DMG: InvokeResponseMessage = - [1702438116.143590][2387:2389] CHIP:DMG: { - [1702438116.143648][2387:2389] CHIP:DMG: suppressResponse = false, - [1702438116.143877][2387:2389] CHIP:DMG: InvokeResponseIBs = - [1702438116.144238][2387:2389] CHIP:DMG: [ - [1702438116.144308][2387:2389] CHIP:DMG: InvokeResponseIB = - [1702438116.144414][2387:2389] CHIP:DMG: { - [1702438116.144476][2387:2389] CHIP:DMG: CommandStatusIB = - [1702438116.144575][2387:2389] CHIP:DMG: { - [1702438116.144646][2387:2389] CHIP:DMG: CommandPathIB = - [1702438116.144723][2387:2389] CHIP:DMG: { - [1702438116.144825][2387:2389] CHIP:DMG: EndpointId = 0x0, - [1702438116.144911][2387:2389] CHIP:DMG: ClusterId = 0x46, - [1702438116.144993][2387:2389] CHIP:DMG: CommandId = 0x2, - [1702438116.145097][2387:2389] CHIP:DMG: }, - [1702438116.145186][2387:2389] CHIP:DMG: - [1702438116.145278][2387:2389] CHIP:DMG: StatusIB = - [1702438116.145357][2387:2389] CHIP:DMG: { - [1702438116.145457][2387:2389] CHIP:DMG: status = 0x00 (SUCCESS), - [1702438116.145538][2387:2389] CHIP:DMG: }, - [1702438116.145616][2387:2389] CHIP:DMG: - [1702438116.145683][2387:2389] CHIP:DMG: }, - [1702438116.145782][2387:2389] CHIP:DMG: - [1702438116.145846][2387:2389] CHIP:DMG: }, - [1702438116.145917][2387:2389] CHIP:DMG: - [1702438116.146004][2387:2389] CHIP:DMG: ], - [1702438116.146078][2387:2389] CHIP:DMG: - [1702438116.146155][2387:2389] CHIP:DMG: InteractionModelRevision = 11 - [1702438116.146213][2387:2389] CHIP:DMG: }, - [1702438116.146382][2387:2389] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0002 Status=0x0 - disabled: true - - - label: "Step 4c: TH reads from the DUT the RegisteredClients attribute." - PICS: ICDM.S.A0003 - verification: | - ./chip-tool icdmanagement read registered-clients 1 0 - - [1702438139.915311][2390:2392] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0003 DataVersion: 2633987690 - [1702438139.915462][2390:2392] CHIP:TOO: RegisteredClients: 1 entries - [1702438139.915616][2390:2392] CHIP:TOO: [1]: { - [1702438139.915667][2390:2392] CHIP:TOO: CheckInNodeID: 112233 - [1702438139.915708][2390:2392] CHIP:TOO: MonitoredSubject: 112233 - [1702438139.915774][2390:2392] CHIP:TOO: FabricIndex: 1 - [1702438139.915818][2390:2392] CHIP:TOO: } - disabled: true - - - label: - "Step 4d: Clear the THs administrator privileges for the ICDM cluster." - verification: | - ./chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 4, "authMode": 2, "subjects": [112233], "targets": null } ]' 1 0 - disabled: true - - - label: - "Step 5a: TH sends RegisterClient command. - CheckInNodeID: - registering clients node ID (CheckInNodeID5) - MonitoredSubject: - monitored subject ID (MonitorSubID5) - Key: shared secret between the - client and the ICD (Key5) - VerificationKey: verification key - (VerificationKey5)" - PICS: ICDM.S.C00.Rsp - verification: | - ./chip-tool icdmanagement register-client 5 5 hex:5555567890abcdef5555567890abcdef 1 0 --VerificationKey hex:abcdef1234567890abcdef1234567890 - On TH(chip-tool) verify that DUT responds with status code as success - - [1702437824.926527][2361:2363] CHIP:DMG: Received Command Response Data, Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0001 - [1702437824.926625][2361:2363] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Command 0x0000_0001 - [1702437824.926835][2361:2363] CHIP:TOO: RegisterClientResponse: { - [1702437824.926901][2361:2363] CHIP:TOO: ICDCounter: 2124479668 - [1702437824.926955][2361:2363] CHIP:TOO: } - disabled: true - - - label: "Step 5b: TH reads from the DUT the RegisteredClients attribute." - PICS: ICDM.S.A0003 - verification: | - ./chip-tool icdmanagement read registered-clients 1 0 - - On TH(Chip-tool), Verify that the DUT response contains a list of 1 registered client of given CheckInNodeID, MonitoredSubject, and Key - - [1702438233.117193][2401:2403] CHIP:TOO: Endpoint: 0 Cluster: 0x0000_0046 Attribute 0x0000_0003 DataVersion: 2633987690 - [1702438233.117356][2401:2403] CHIP:TOO: RegisteredClients: 2 entries - [1702438233.117510][2401:2403] CHIP:TOO: [1]: { - [1702438233.117559][2401:2403] CHIP:TOO: CheckInNodeID: 112233 - [1702438233.117603][2401:2403] CHIP:TOO: MonitoredSubject: 112233 - [1702438233.117669][2401:2403] CHIP:TOO: FabricIndex: 1 - [1702438233.117713][2401:2403] CHIP:TOO: } - [1702438233.117772][2401:2403] CHIP:TOO: [2]: { - [1702438233.117816][2401:2403] CHIP:TOO: CheckInNodeID: 5 - [1702438233.117859][2401:2403] CHIP:TOO: MonitoredSubject: 5 - [1702438233.117902][2401:2403] CHIP:TOO: FabricIndex: 1 - [1702438233.117944][2401:2403] CHIP:TOO: } - disabled: true - - - label: - "Step 6: TH sends UnregisterClient command with the CheckInNodeID from - Step 5a and an invalid VerificationKey. - CheckInNodeID: registering - clients node ID (CheckInNodeID5) - VerificationKey: invalid - verification key (VerificationKey6)" - PICS: ICDM.S.C02.Rsp - verification: | - ./chip-tool icdmanagement unregister-client 5 1 0 --VerificationKey hex:abcdef1234567890 - - [1703268222.346310][2758:2760] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0002 Status=0x1 - [1703268222.346412][2758:2760] CHIP:TOO: Error: IM Error 0x00000501: General error: 0x01 (FAILURE) - disabled: true - - - label: - "Step 7: TH sends UnregisterClient command with the CheckInNodeID from - Step 5a and different VerificationKey. - CheckInNodeID: registering - clients node ID (CheckInNodeID5) - VerificationKey: valid verification - key (VerificationKey7)" - PICS: ICDM.S.C02.Rsp - verification: | - ./chip-tool icdmanagement unregister-client 5 1 0 --VerificationKey hex:abcdef1234567890abcdef1234500000 - - [1703268200.542869][2755:2757] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0002 Status=0x1 - [1703268200.543007][2755:2757] CHIP:TOO: Error: IM Error 0x00000501: General error: 0x01 (FAILURE) - disabled: true - - - label: - "Step 8: TH sends UnregisterClient command with the CheckInNodeID and - VerificationKey from Step 5a. - CheckInNodeID: registering clients - node ID (CheckInNodeID5) - VerificationKey: verification key - (VerificationKey5)" - PICS: ICDM.S.C02.Rsp - verification: | - ./chip-tool icdmanagement unregister-client 5 1 0 --VerificationKey hex:abcdef1234567890abcdef1234567890 - - [1702438116.143490][2387:2389] CHIP:DMG: InvokeResponseMessage = - [1702438116.143590][2387:2389] CHIP:DMG: { - [1702438116.143648][2387:2389] CHIP:DMG: suppressResponse = false, - [1702438116.143877][2387:2389] CHIP:DMG: InvokeResponseIBs = - [1702438116.144238][2387:2389] CHIP:DMG: [ - [1702438116.144308][2387:2389] CHIP:DMG: InvokeResponseIB = - [1702438116.144414][2387:2389] CHIP:DMG: { - [1702438116.144476][2387:2389] CHIP:DMG: CommandStatusIB = - [1702438116.144575][2387:2389] CHIP:DMG: { - [1702438116.144646][2387:2389] CHIP:DMG: CommandPathIB = - [1702438116.144723][2387:2389] CHIP:DMG: { - [1702438116.144825][2387:2389] CHIP:DMG: EndpointId = 0x0, - [1702438116.144911][2387:2389] CHIP:DMG: ClusterId = 0x46, - [1702438116.144993][2387:2389] CHIP:DMG: CommandId = 0x2, - [1702438116.145097][2387:2389] CHIP:DMG: }, - [1702438116.145186][2387:2389] CHIP:DMG: - [1702438116.145278][2387:2389] CHIP:DMG: StatusIB = - [1702438116.145357][2387:2389] CHIP:DMG: { - [1702438116.145457][2387:2389] CHIP:DMG: status = 0x00 (SUCCESS), - [1702438116.145538][2387:2389] CHIP:DMG: }, - [1702438116.145616][2387:2389] CHIP:DMG: - [1702438116.145683][2387:2389] CHIP:DMG: }, - [1702438116.145782][2387:2389] CHIP:DMG: - [1702438116.145846][2387:2389] CHIP:DMG: }, - [1702438116.145917][2387:2389] CHIP:DMG: - [1702438116.146004][2387:2389] CHIP:DMG: ], - [1702438116.146078][2387:2389] CHIP:DMG: - [1702438116.146155][2387:2389] CHIP:DMG: InteractionModelRevision = 11 - [1702438116.146213][2387:2389] CHIP:DMG: }, - [1702438116.146382][2387:2389] CHIP:DMG: Received Command Response Status for Endpoint=0 Cluster=0x0000_0046 Command=0x0000_0002 Status=0x0 - disabled: true diff --git a/src/app/tests/suites/manualTests.json b/src/app/tests/suites/manualTests.json index 7b99318fe6c9fd..bbb86f7092b715 100644 --- a/src/app/tests/suites/manualTests.json +++ b/src/app/tests/suites/manualTests.json @@ -119,7 +119,6 @@ "Identify": ["Test_TC_I_3_2"], "IcdManagement": [ "Test_TC_ICDM_3_2", - "Test_TC_ICDM_3_3", "Test_TC_ICDM_4_1", "Test_TC_ICDM_5_1" ], diff --git a/src/python_testing/TC_ICDM_3_3.py b/src/python_testing/TC_ICDM_3_3.py new file mode 100644 index 00000000000000..cb8d1bd7bcbbcd --- /dev/null +++ b/src/python_testing/TC_ICDM_3_3.py @@ -0,0 +1,380 @@ + +# +# Copyright (c) 2023 Project CHIP Authors +# All rights reserved. +# +# 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. +# + +# See https://github.com/project-chip/connectedhomeip/blob/master/docs/testing/python.md#defining-the-ci-test-arguments +# for details about the block below. +# +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${LIT_ICD_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --PICS src/app/tests/suites/certification/ci-pics-values --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + +import logging +from dataclasses import dataclass + +import chip.clusters as Clusters +from chip.interaction_model import InteractionModelError, Status +from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + +logger = logging.getLogger(__name__) + +kRootEndpointId = 0 + +cluster = Clusters.Objects.IcdManagement +commands = cluster.Commands +ClientTypeEnum = cluster.Enums.ClientTypeEnum + + +@dataclass +class Client: + checkInNodeID: int + subjectId: int + key: bytes + clientType: ClientTypeEnum + + +# +# Test Input Data +# +kIncorrectKey = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1a" +kInvalidKey = b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e1g" + +client1 = Client( + checkInNodeID=1, + subjectId=1, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + clientType=ClientTypeEnum.kEphemeral +) + +client2 = Client( + checkInNodeID=2, + subjectId=2, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + clientType=ClientTypeEnum.kEphemeral +) + +client3 = Client( + checkInNodeID=3, + subjectId=3, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + clientType=ClientTypeEnum.kEphemeral +) + +client4 = Client( + checkInNodeID=4, + subjectId=4, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + clientType=ClientTypeEnum.kEphemeral +) + +# Client 5 skipped in the Test Plan steps +client6 = Client( + checkInNodeID=6, + subjectId=6, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + clientType=ClientTypeEnum.kEphemeral +) + +# Client 7 skipped in the Test Plan steps +client8 = Client( + checkInNodeID=8, + subjectId=8, + key=b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", + clientType=ClientTypeEnum.kEphemeral +) + + +class TC_ICDM_3_3(MatterBaseTest): + + # + # Class Helper functions + # + async def _read_icdm_attribute_expect_success(self, attribute): + return await self.read_single_attribute_check_success(endpoint=kRootEndpointId, cluster=cluster, attribute=attribute) + + async def _send_single_icdm_command(self, command): + return await self.send_single_cmd(command, endpoint=kRootEndpointId) + # + # Test Harness Helpers + # + + def desc_TC_ICDM_3_3(self) -> str: + """Returns a description of this test""" + return "[TC-ICDM-3.3] Register/Unregister Clients with DUT as Server" + + def steps_TC_ICDM_3_3(self) -> list[TestStep]: + steps = [ + TestStep(0, "Commissioning, already done", is_commissioning=True), + TestStep("1a", "TH reads from the DUT the RegisteredClients attribute."), + TestStep("1b", "TH sends UnregisterClient command with CheckInNodeID1, where CheckInNodeID1 can be any random node ID."), + TestStep("2a", "TH sends RegisterClient command."), + TestStep("2b", "TH reads from the DUT the RegisteredClients attribute."), + TestStep(3, "TH sends UnregisterClient command with the CheckInNodeID3."), + TestStep("4a", "TH sends UnregisterClient command with the CheckInNodeID2."), + TestStep("4b", "TH reads from the DUT the RegisteredClients attribute."), + TestStep("5a", "TH sends RegisterClient command."), + TestStep("5b", "TH reads from the DUT the RegisteredClients attribute."), + TestStep("5c", "TH sends UnregisterClient command with the CheckInNodeID4 as in Step 5a and an invalid VerificationKey5."), + TestStep("5d", "TH reads from the DUT the RegisteredClients attribute."), + TestStep("6a", "TH sends RegisterClient command."), + TestStep("6b", "TH reads from the DUT the RegisteredClients attribute."), + TestStep("6c", "TH sends UnregisterClient command with the CheckInNodeID6 as in Step 6a and a wrong VerificationKey7."), + TestStep("6d", "TH reads from the DUT the RegisteredClients attribute."), + TestStep(7, "Set the TH to Manage privilege for ICDM cluster."), + TestStep("8a", "TH sends RegisterClient command."), + TestStep("8b", "TH sends UnregisterClient command with the CheckInNodeID8 from Step 8a and an invalid VerificationKey9."), + TestStep("8c", "TH sends UnregisterClient command with the CheckInNodeID8 from Step 8a and a valid wrong VerificationKey10."), + TestStep("8d", "TH sends UnregisterClient command with the CheckInNodeID8 and VerificationKey8 from Step 8a."), + ] + return steps + + def pics_TC_ICDM_3_3(self) -> list[str]: + """ This function returns a list of PICS for this test case that must be True for the test to be run""" + pics = [ + "ICDM.S", + "ICDM.S.F00" + ] + return pics + + # + # ICDM 3.3 Test Body + # + + @async_test_body + async def test_TC_ICDM_3_3(self): + + cluster = Clusters.Objects.IcdManagement + attributes = cluster.Attributes + + # Pre-Condition: Commissioning + self.step(0) + + self.step("1a") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + + for client in registeredClients: + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client.checkInNodeID)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + # Try / Case for the Test Plan post condition + try: + self.step("1b") + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client1.checkInNodeID)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.NotFound, "Unexpected error returned") + pass + + self.step("2a") + try: + await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=client2.checkInNodeID, monitoredSubject=client2.subjectId, key=client2.key, clientType=client2.clientType)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("2b") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + # Validate list size + asserts.assert_equal(len(registeredClients), 1, + "The expected length of RegisteredClients is 1. List has the wrong size.") + + # Validate entry values + asserts.assert_equal( + registeredClients[0].checkInNodeID, client2.checkInNodeID, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].monitoredSubject, client2.subjectId, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].clientType, client2.clientType, "The read attribute does not match the registered value.") + + self.step(3) + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client3.checkInNodeID)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.NotFound, "Unexpected error returned") + + self.step("4a") + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client2.checkInNodeID)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("4b") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + asserts.assert_equal(len(registeredClients), 0, + "The RegisteredClients list must be empty. List has the wrong size.") + + self.step("5a") + try: + await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=client4.checkInNodeID, monitoredSubject=client4.subjectId, key=client4.key, clientType=client4.clientType)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("5b") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + # Validate list size + asserts.assert_equal(len(registeredClients), 1, + "The expected length of RegisteredClients is 1. List has the wrong size.") + + # Validate entry values + asserts.assert_equal( + registeredClients[0].checkInNodeID, client4.checkInNodeID, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].monitoredSubject, client4.subjectId, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].clientType, client4.clientType, "The read attribute does not match the registered value.") + + self.step("5c") + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client4.checkInNodeID, verificationKey=kInvalidKey)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("5d") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + asserts.assert_equal(len(registeredClients), 0, + "The RegisteredClients list must be empty. List has the wrong size.") + + self.step("6a") + try: + await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=client6.checkInNodeID, monitoredSubject=client6.subjectId, key=client6.key, clientType=client6.clientType)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("6b") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + # Validate list size + asserts.assert_equal(len(registeredClients), 1, + "The expected length of RegisteredClients is 1. List has the wrong size.") + + # Validate entry values + asserts.assert_equal( + registeredClients[0].checkInNodeID, client6.checkInNodeID, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].monitoredSubject, client6.subjectId, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].clientType, client6.clientType, "The read attribute does not match the registered value.") + + self.step("6c") + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client6.checkInNodeID, verificationKey=kIncorrectKey)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("6d") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + asserts.assert_equal(len(registeredClients), 0, + "The RegisteredClients list must be empty. List has the wrong size.") + self.step(7) + ac = Clusters.AccessControl + previousAcl = await self.read_single_attribute_check_success(cluster=ac, attribute=ac.Attributes.Acl) + newAcls = [] + + # Set Admin permissions on Access Control cluster + newAclEntry = ac.Structs.AccessControlEntryStruct(privilege=ac.Enums.AccessControlEntryPrivilegeEnum.kAdminister, + authMode=ac.Enums.AccessControlEntryAuthModeEnum.kCase, + subjects=previousAcl[0].subjects, targets=[ac.Structs.AccessControlTargetStruct( + cluster=Clusters.AccessControl.id)], fabricIndex=previousAcl[0].fabricIndex + ) + newAcls.append(newAclEntry) + + # Set Manage permissions on ICD Management cluster + newAclEntry = ac.Structs.AccessControlEntryStruct(privilege=ac.Enums.AccessControlEntryPrivilegeEnum.kManage, + authMode=ac.Enums.AccessControlEntryAuthModeEnum.kCase, + subjects=previousAcl[0].subjects, targets=[ac.Structs.AccessControlTargetStruct( + cluster=Clusters.IcdManagement.id)], fabricIndex=previousAcl[0].fabricIndex + ) + newAcls.append(newAclEntry) + + try: + await self.default_controller.WriteAttribute(nodeid=self.dut_node_id, attributes=[(0, ac.Attributes.Acl(newAcls))]) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("8a") + try: + await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=client8.checkInNodeID, monitoredSubject=client8.subjectId, key=client8.key, clientType=client8.clientType)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + self.step("8b") + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client8.checkInNodeID, verificationKey=kInvalidKey)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Failure, "Unexpected error returned") + + self.step("8c") + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client8.checkInNodeID, verificationKey=kIncorrectKey)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Failure, "Unexpected error returned") + self.step("8d") + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client8.checkInNodeID, verificationKey=client8.key)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + # Post-Condition steps + finally: + # Reset ACLs + try: + await self.default_controller.WriteAttribute(nodeid=self.dut_node_id, attributes=[(0, ac.Attributes.Acl(previousAcl))]) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + # Clear all RegisteredClients + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + + for client in registeredClients: + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client.checkInNodeID)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + + +if __name__ == "__main__": + default_matter_test_main() From 157aa4002e3ab98a13d8a083ba6d8e1d9f89e601 Mon Sep 17 00:00:00 2001 From: mkardous-silabs <84793247+mkardous-silabs@users.noreply.github.com> Date: Sat, 3 Aug 2024 23:08:58 -0400 Subject: [PATCH 05/41] Update ICDM 3.1 Test Script (#34733) --- src/python_testing/TC_ICDM_3_1.py | 229 ++++++++++++++---------------- 1 file changed, 103 insertions(+), 126 deletions(-) diff --git a/src/python_testing/TC_ICDM_3_1.py b/src/python_testing/TC_ICDM_3_1.py index 938479a9147f5f..f20e2816723a28 100644 --- a/src/python_testing/TC_ICDM_3_1.py +++ b/src/python_testing/TC_ICDM_3_1.py @@ -72,32 +72,22 @@ def desc_TC_ICDM_3_1(self) -> str: def steps_TC_ICDM_3_1(self) -> list[TestStep]: steps = [ - TestStep("0a", "Commissioning, already done", + TestStep(0, "Commissioning, already done", is_commissioning=True), - TestStep( - "0b", "TH reads from the DUT the RegisteredClients attribute. RegisteredClients is empty."), - TestStep( - "1a", "TH reads from the DUT the ClientsSupportedPerFabric attribute."), - TestStep( - "1b", "TH reads from the DUT the ICDCounter attribute."), + TestStep("1a", "TH reads from the DUT the RegisteredClients attribute. RegisteredClients is empty."), + TestStep("1b", "TH reads from the DUT the ClientsSupportedPerFabric attribute."), + TestStep("1c", "TH reads from the DUT the ICDCounter attribute."), TestStep(2, "TH sends RegisterClient command."), TestStep(3, "TH reads from the DUT the RegisteredClients attribute."), - TestStep( - 4, "If len(RegisteredClients) is less than ClientsSupportedPerFabric, TH repeats RegisterClient command with different CheckInNodeID(s) until the number of entries in RegisteredClients equals ClientsSupportedPerFabric."), + TestStep(4, "If len(RegisteredClients) is less than ClientsSupportedPerFabric, TH repeats RegisterClient command with different CheckInNodeID(s) until the number of entries in RegisteredClients equals ClientsSupportedPerFabric."), TestStep(5, "TH reads from the DUT the RegisteredClients attribute."), - TestStep( - 6, "TH sends RegisterClient command with a different CheckInNodeID."), - TestStep( - 7, "TTH sends UnregisterClient command with the CheckInNodeID from Step 6."), - TestStep( - 8, "TH sends UnregisterClient command with the CheckInNodeID from Step 2."), - TestStep( - 9, "TH reads from the DUT the RegisteredClients attribute."), - TestStep( - 10, "Repeat Step 9 with the rest of CheckInNodeIDs from the list of RegisteredClients from Step 4, if any."), + TestStep(6, "TH sends RegisterClient command with a different CheckInNodeID."), + TestStep(7, "TTH sends UnregisterClient command with the CheckInNodeID from Step 6."), + TestStep(8, "TH sends UnregisterClient command with the CheckInNodeID from Step 2."), + TestStep(9, "TH reads from the DUT the RegisteredClients attribute."), + TestStep(10, "Repeat Step 9 with the rest of CheckInNodeIDs from the list of RegisteredClients from Step 4, if any."), TestStep(11, "TH reads from the DUT the RegisteredClients attribute."), - TestStep( - 12, "TH sends UnregisterClient command with the CheckInNodeID from Step 2."), + TestStep(12, "TH sends UnregisterClient command with the CheckInNodeID from Step 2."), ] return steps @@ -120,10 +110,10 @@ async def test_TC_ICDM_3_1(self): attributes = cluster.Attributes # Pre-Condition: Commissioning - self.step("0a") + self.step(0) - # Pre-Condition: Empty RegisteredClients attribute for all registrations - self.step("0b") + # Empty RegisteredClients attribute for all registrations + self.step("1a") registeredClients = await self._read_icdm_attribute_expect_success( attributes.RegisteredClients) @@ -135,56 +125,51 @@ async def test_TC_ICDM_3_1(self): e.status, Status.Success, "Unexpected error returned") pass - self.step("1a") - if self.pics_guard(self.check_pics("ICDM.S.A0005")): - clientsSupportedPerFabric = await self._read_icdm_attribute_expect_success( - attributes.ClientsSupportedPerFabric) - self.step("1b") - if self.pics_guard(self.check_pics("ICDM.S.A0005")): - icdCounter = await self._read_icdm_attribute_expect_success(attributes.ICDCounter) + clientsSupportedPerFabric = await self._read_icdm_attribute_expect_success( + attributes.ClientsSupportedPerFabric) + + self.step("1c") + icdCounter = await self._read_icdm_attribute_expect_success(attributes.ICDCounter) self.step(2) - if self.pics_guard(self.check_pics("ICDM.S.C00.Rsp")): - try: - response = await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=kStep2CheckInNodeId, monitoredSubject=kStep2MonitoredSubjectStep2, key=kStep2Key, clientType=clientTypeEnum.kEphemeral)) - except InteractionModelError as e: - asserts.assert_equal( - e.status, Status.Success, "Unexpected error returned") - pass + try: + response = await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=kStep2CheckInNodeId, monitoredSubject=kStep2MonitoredSubjectStep2, key=kStep2Key, clientType=clientTypeEnum.kEphemeral)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + pass - # Validate response contains the ICDCounter - asserts.assert_greater_equal(response.ICDCounter, icdCounter, - "The ICDCounter in the response does not match the read ICDCounter.") + # Validate response contains the ICDCounter + asserts.assert_greater_equal(response.ICDCounter, icdCounter, + "The ICDCounter in the response does not match the read ICDCounter.") self.step(3) - if self.pics_guard(self.check_pics("ICDM.S.A0003")): - registeredClients = await self._read_icdm_attribute_expect_success( - attributes.RegisteredClients) - # Validate list size - asserts.assert_equal(len(registeredClients), 1, - "The expected length of RegisteredClients is 1. List has the wrong size.") - - # Validate entry values - asserts.assert_equal( - registeredClients[0].checkInNodeID, kStep2CheckInNodeId, "The read attribute does not match the registered value.") - asserts.assert_equal( - registeredClients[0].monitoredSubject, kStep2MonitoredSubjectStep2, "The read attribute does not match the registered value.") - asserts.assert_equal( - registeredClients[0].clientType, clientTypeEnum.kEphemeral, "The read attribute does not match the registered value.") + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) + # Validate list size + asserts.assert_equal(len(registeredClients), 1, + "The expected length of RegisteredClients is 1. List has the wrong size.") + + # Validate entry values + asserts.assert_equal( + registeredClients[0].checkInNodeID, kStep2CheckInNodeId, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].monitoredSubject, kStep2MonitoredSubjectStep2, "The read attribute does not match the registered value.") + asserts.assert_equal( + registeredClients[0].clientType, clientTypeEnum.kEphemeral, "The read attribute does not match the registered value.") self.step(4) - if self.pics_guard(self.check_pics("ICDM.S.C00.Rsp")): - if (len(registeredClients) < clientsSupportedPerFabric): - newClients = [] - # Generate new clients data - for i in range(clientsSupportedPerFabric - len(registeredClients)): - newClients.append({ - "checkInNodeID": i + 1, - "monitoredSubject": i + 1, - "key": os.urandom(16), - "clientType": clientTypeEnum.kPermanent - }) + if (len(registeredClients) < clientsSupportedPerFabric): + newClients = [] + # Generate new clients data + for i in range(clientsSupportedPerFabric - len(registeredClients)): + newClients.append({ + "checkInNodeID": i + 1, + "monitoredSubject": i + 1, + "key": os.urandom(16), + "clientType": clientTypeEnum.kPermanent + }) for client in newClients: try: @@ -199,84 +184,76 @@ async def test_TC_ICDM_3_1(self): "The ICDCounter in the response does not match the read ICDCounter.") self.step(5) - if self.pics_guard(self.check_pics("ICDM.S.A0003")): - registeredClients = await self._read_icdm_attribute_expect_success( - attributes.RegisteredClients) + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) - # Validate list size - asserts.assert_equal(len(registeredClients[1:]), len(newClients), - "The expected length of RegisteredClients is clientsSupportedPerFabric. List has the wrong size.") + # Validate list size + asserts.assert_equal(len(registeredClients[1:]), len(newClients), + "The expected length of RegisteredClients is clientsSupportedPerFabric. List has the wrong size.") - for client, expectedClient in zip(registeredClients[1:], newClients): - asserts.assert_equal( - client.checkInNodeID, expectedClient["checkInNodeID"], "The read attribute does not match the registered value.") - asserts.assert_equal( - client.monitoredSubject, expectedClient["monitoredSubject"], "The read attribute does not match the registered value.") - asserts.assert_equal( - client.clientType, expectedClient["clientType"], "The read attribute does not match the registered value.") + for client, expectedClient in zip(registeredClients[1:], newClients): + asserts.assert_equal( + client.checkInNodeID, expectedClient["checkInNodeID"], "The read attribute does not match the registered value.") + asserts.assert_equal( + client.monitoredSubject, expectedClient["monitoredSubject"], "The read attribute does not match the registered value.") + asserts.assert_equal( + client.clientType, expectedClient["clientType"], "The read attribute does not match the registered value.") self.step(6) - if self.pics_guard(self.check_pics("ICDM.S.C00.Rsp")): - try: - response = await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=0xFFFF, monitoredSubject=0xFFFF, key=os.urandom(16), clientType=clientTypeEnum.kPermanent)) - except InteractionModelError as e: - asserts.assert_equal( - e.status, Status.ResourceExhausted, "Unexpected error returned") - pass + try: + response = await self._send_single_icdm_command(commands.RegisterClient(checkInNodeID=0xFFFF, monitoredSubject=0xFFFF, key=os.urandom(16), clientType=clientTypeEnum.kPermanent)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.ResourceExhausted, "Unexpected error returned") + pass self.step(7) - if self.pics_guard(self.check_pics("ICDM.S.C02.Rsp")): - try: - await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=0xFFFF)) - except InteractionModelError as e: - asserts.assert_equal( - e.status, Status.NotFound, "Unexpected error returned") - pass + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=0xFFFF)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.NotFound, "Unexpected error returned") + pass self.step(8) - if self.pics_guard(self.check_pics("ICDM.S.C02.Rsp")): - try: - await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=kStep2CheckInNodeId)) - except InteractionModelError as e: - asserts.assert_equal( - e.status, Status.Success, "Unexpected error returned") - pass + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=kStep2CheckInNodeId)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + pass self.step(9) - if self.pics_guard(self.check_pics("ICDM.S.A0003")): - registeredClients = await self._read_icdm_attribute_expect_success( - attributes.RegisteredClients) + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) - for client in registeredClients: - asserts.assert_not_equal(client.checkInNodeID, kStep2CheckInNodeId, - "CheckInNodeID was unregistered. It should not be present in the attribute list.") + for client in registeredClients: + asserts.assert_not_equal(client.checkInNodeID, kStep2CheckInNodeId, + "CheckInNodeID was unregistered. It should not be present in the attribute list.") self.step(10) - if self.pics_guard(self.check_pics("ICDM.S.C02.Rsp")): - for client in newClients: - try: - await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client["checkInNodeID"])) - except InteractionModelError as e: - asserts.assert_equal( - e.status, Status.Success, "Unexpected error returned") - pass + for client in newClients: + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=client["checkInNodeID"])) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.Success, "Unexpected error returned") + pass self.step(11) - if self.pics_guard(self.check_pics("ICDM.S.A0003")): - registeredClients = await self._read_icdm_attribute_expect_success( - attributes.RegisteredClients) + registeredClients = await self._read_icdm_attribute_expect_success( + attributes.RegisteredClients) - asserts.assert_true( - not registeredClients, "This list should empty. An element did not get deleted.") + asserts.assert_true( + not registeredClients, "This list should empty. An element did not get deleted.") self.step(12) - if self.pics_guard(self.check_pics("ICDM.S.C02.Rsp")): - try: - await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=kStep2CheckInNodeId)) - except InteractionModelError as e: - asserts.assert_equal( - e.status, Status.NotFound, "Unexpected error returned") - pass + try: + await self._send_single_icdm_command(commands.UnregisterClient(checkInNodeID=kStep2CheckInNodeId)) + except InteractionModelError as e: + asserts.assert_equal( + e.status, Status.NotFound, "Unexpected error returned") + pass if __name__ == "__main__": From 999c1dd734eb2d78688ee9883d2290eac48caa11 Mon Sep 17 00:00:00 2001 From: Anton Usmansky Date: Sun, 4 Aug 2024 13:32:03 +0300 Subject: [PATCH 06/41] OnOffServer: ignore StartUpOnOff value after reboot due to OTA (#34160) * feat: restore onOffValue after reboot during OTA applying * fix: style * fix: set onOffValueForStartUp in case of reserved values --- .../clusters/on-off-server/on-off-server.cpp | 74 ++++++++++++------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/src/app/clusters/on-off-server/on-off-server.cpp b/src/app/clusters/on-off-server/on-off-server.cpp index 98dfaf9da02c3e..d18aa09383a0d5 100644 --- a/src/app/clusters/on-off-server/on-off-server.cpp +++ b/src/app/clusters/on-off-server/on-off-server.cpp @@ -45,6 +45,7 @@ #endif // MATTER_DM_PLUGIN_MODE_BASE #include +#include #include using namespace chip; @@ -52,6 +53,8 @@ using namespace chip::app::Clusters; using namespace chip::app::Clusters::OnOff; using chip::Protocols::InteractionModel::Status; +using BootReasonType = GeneralDiagnostics::BootReasonEnum; + namespace { #ifdef MATTER_DM_PLUGIN_MODE_BASE @@ -95,6 +98,22 @@ bool IsKnownEnumValue(EnumType value) return (EnsureKnownEnumValue(value) != EnumType::kUnknownEnumValue); } +BootReasonType GetBootReason() +{ + BootReasonType bootReason = BootReasonType::kUnspecified; + + CHIP_ERROR error = DeviceLayer::GetDiagnosticDataProvider().GetBootReason(bootReason); + if (error != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Unable to retrieve boot reason: %" CHIP_ERROR_FORMAT, error.Format()); + bootReason = BootReasonType::kUnspecified; + } + + ChipLogProgress(Zcl, "Boot reason: %u", to_underlying(bootReason)); + + return bootReason; +} + } // namespace #ifdef MATTER_DM_PLUGIN_LEVEL_CONTROL @@ -537,35 +556,36 @@ Status OnOffServer::getOnOffValueForStartUp(chip::EndpointId endpoint, bool & on { app::DataModel::Nullable startUpOnOff; Status status = Attributes::StartUpOnOff::Get(endpoint, startUpOnOff); - if (status == Status::Success) + VerifyOrReturnError(status == Status::Success, status); + + bool currentOnOff = false; + status = Attributes::OnOff::Get(endpoint, ¤tOnOff); + VerifyOrReturnError(status == Status::Success, status); + + if (startUpOnOff.IsNull() || GetBootReason() == BootReasonType::kSoftwareUpdateCompleted) { - // Initialise updated value to 0 - bool updatedOnOff = false; - status = Attributes::OnOff::Get(endpoint, &updatedOnOff); - if (status == Status::Success) - { - if (!startUpOnOff.IsNull()) - { - switch (startUpOnOff.Value()) - { - case OnOff::StartUpOnOffEnum::kOff: - updatedOnOff = false; // Off - break; - case OnOff::StartUpOnOffEnum::kOn: - updatedOnOff = true; // On - break; - case OnOff::StartUpOnOffEnum::kToggle: - updatedOnOff = !updatedOnOff; - break; - default: - // All other values 0x03- 0xFE are reserved - no action. - break; - } - } - onOffValueForStartUp = updatedOnOff; - } + onOffValueForStartUp = currentOnOff; + return Status::Success; } - return status; + + switch (startUpOnOff.Value()) + { + case OnOff::StartUpOnOffEnum::kOff: + onOffValueForStartUp = false; // Off + break; + case OnOff::StartUpOnOffEnum::kOn: + onOffValueForStartUp = true; // On + break; + case OnOff::StartUpOnOffEnum::kToggle: + onOffValueForStartUp = !currentOnOff; + break; + default: + // All other values 0x03- 0xFE are reserved - no action. + onOffValueForStartUp = currentOnOff; + break; + } + + return Status::Success; } bool OnOffServer::offCommand(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath) From bbef51a418c17d5c2eaf667388cfec70383f524d Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Sun, 4 Aug 2024 10:18:15 -0400 Subject: [PATCH 07/41] Fixed discrepancy between script and test plan for pics in step 9e (#34734) --- src/python_testing/TC_CC_10_1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python_testing/TC_CC_10_1.py b/src/python_testing/TC_CC_10_1.py index 3f1e40278bb0c6..dee2dfad442485 100644 --- a/src/python_testing/TC_CC_10_1.py +++ b/src/python_testing/TC_CC_10_1.py @@ -502,7 +502,7 @@ async def test_TC_CC_10_1(self): asserts.assert_equal(ColorLoopDirection, 1, "ColorLoopDirection is not 1") self.step("9e") - if self.pics_guard(self.check_pics("CC.S.C44.Rsp")): + if self.pics_guard(self.check_pics("CC.S.F02")): ColorLoopTime = await self.read_single_attribute_check_success(cluster, attributes.ColorLoopTime) asserts.assert_equal(ColorLoopTime, 5, "ColorLoopTime is not 5") From c53d771a45f842e4675e7b95da47385b873c316e Mon Sep 17 00:00:00 2001 From: William Date: Mon, 5 Aug 2024 13:02:38 +0100 Subject: [PATCH 08/41] Updates Service Area with name changes since 0.7 (#34711) * Updated the golabl data type's XMLs, removing the cluster entries. * Zap generated after XML update. * Fixed namespaces used of global structs. * Restyled by clang-format * Renamed LocationInfoStruct to AreaInfoStruct. * Zap generated after XML update. * Renamed LocationStruct to AreaStruct and its LocationID and LocationDesc fields. * Zap generated after XML update. * Updated SDK and example code to match the new naming. * Updated the ProgressStruct's LocationID name to AreaID. * Zap generated after XML update. * Updated the SDK code following name changes. * Updated the SelectLocationsStatus and SkipLocationStatus enum names and some of their enums. * Zap generated after XML update. * Updated the SelectLocationsStatus and SkipCurrentLocationStatus names and their enum names. * Updated the names of the SupportedLocations, SelectedLocations and CurrentLocation attributes. * Zap generated after XML update. * Updated the changed names in the SDK. * Updated the service area command names in XML. * Zap generated after XML update. * Updated the service area command names in the SDK. * Updated the rvc-example zap file. * Refactored LocationStructureWrapper to AreaStructureWrapper. * Restyled by clang-format * Regenerated zap files due to changes upsteram. * Removed unused generated file. * spacing changes form zap regen. * Fixed minor mistake during merge. --------- Co-authored-by: Restyled.io --- .../include/rvc-service-area-delegate.h | 36 +- examples/rvc-app/rvc-common/rvc-app.matter | 60 ++-- examples/rvc-app/rvc-common/rvc-app.zap | 21 +- .../src/rvc-service-area-delegate.cpp | 120 +++---- .../service-area-cluster-objects.h | 110 +++--- .../service-area-delegate.cpp | 26 +- .../service-area-delegate.h | 108 +++--- .../service-area-server.cpp | 331 +++++++++--------- .../service-area-server/service-area-server.h | 82 ++--- .../data-model/chip/service-area-cluster.xml | 54 +-- .../zcl/zcl-with-test-extensions.json | 2 +- src/app/zap-templates/zcl/zcl.json | 2 +- .../data_model/controller-clusters.matter | 46 +-- .../chip/devicecontroller/ChipClusters.java | 88 ++--- .../chip/devicecontroller/ChipStructs.java | 86 ++--- .../devicecontroller/ClusterIDMapping.java | 18 +- .../devicecontroller/ClusterInfoMapping.java | 44 +-- .../devicecontroller/ClusterReadMapping.java | 42 +-- .../chip/devicecontroller/cluster/files.gni | 4 +- ...kt => ServiceAreaClusterAreaInfoStruct.kt} | 13 +- ...uct.kt => ServiceAreaClusterAreaStruct.kt} | 33 +- .../ServiceAreaClusterProgressStruct.kt | 17 +- .../cluster/clusters/ServiceAreaCluster.kt | 128 ++++--- .../java/matter/controller/cluster/files.gni | 4 +- ...kt => ServiceAreaClusterAreaInfoStruct.kt} | 13 +- ...uct.kt => ServiceAreaClusterAreaStruct.kt} | 33 +- .../ServiceAreaClusterProgressStruct.kt | 17 +- .../CHIPAttributeTLVValueDecoder.cpp | 204 ++++++----- .../python/chip/clusters/CHIPClusters.py | 12 +- .../python/chip/clusters/Objects.py | 72 ++-- .../MTRAttributeSpecifiedCheck.mm | 6 +- .../MTRAttributeTLVValueDecoder.mm | 62 ++-- .../CHIP/zap-generated/MTRBaseClusters.h | 64 ++-- .../CHIP/zap-generated/MTRBaseClusters.mm | 68 ++-- .../CHIP/zap-generated/MTRClusterConstants.h | 14 +- .../CHIP/zap-generated/MTRClusterNames.mm | 12 +- .../CHIP/zap-generated/MTRClusters.h | 12 +- .../CHIP/zap-generated/MTRClusters.mm | 32 +- .../zap-generated/MTRCommandPayloadsObjc.h | 14 +- .../zap-generated/MTRCommandPayloadsObjc.mm | 60 ++-- .../MTRCommandPayloads_Internal.h | 12 +- .../CHIP/zap-generated/MTRStructsObjc.h | 10 +- .../CHIP/zap-generated/MTRStructsObjc.mm | 24 +- .../zap-generated/cluster-enums-check.h | 14 +- .../app-common/zap-generated/cluster-enums.h | 24 +- .../zap-generated/cluster-objects.cpp | 60 ++-- .../zap-generated/cluster-objects.h | 119 ++++--- .../app-common/zap-generated/ids/Attributes.h | 12 +- .../app-common/zap-generated/ids/Commands.h | 16 +- .../zap-generated/cluster/Commands.h | 72 ++-- .../cluster/ComplexArgumentParser.cpp | 54 ++- .../cluster/ComplexArgumentParser.h | 8 +- .../cluster/logging/DataModelLogger.cpp | 46 +-- .../cluster/logging/DataModelLogger.h | 8 +- .../zap-generated/cluster/Commands.h | 234 ++++++------- 55 files changed, 1418 insertions(+), 1465 deletions(-) rename src/controller/java/generated/java/chip/devicecontroller/cluster/structs/{ServiceAreaClusterLocationInfoStruct.kt => ServiceAreaClusterAreaInfoStruct.kt} (92%) rename src/controller/java/generated/java/chip/devicecontroller/cluster/structs/{ServiceAreaClusterLocationStruct.kt => ServiceAreaClusterAreaStruct.kt} (67%) rename src/controller/java/generated/java/matter/controller/cluster/structs/{ServiceAreaClusterLocationInfoStruct.kt => ServiceAreaClusterAreaInfoStruct.kt} (92%) rename src/controller/java/generated/java/matter/controller/cluster/structs/{ServiceAreaClusterLocationStruct.kt => ServiceAreaClusterAreaStruct.kt} (67%) diff --git a/examples/rvc-app/rvc-common/include/rvc-service-area-delegate.h b/examples/rvc-app/rvc-common/include/rvc-service-area-delegate.h index e170d2ffeb35ce..40f312ffb78c2f 100644 --- a/examples/rvc-app/rvc-common/include/rvc-service-area-delegate.h +++ b/examples/rvc-app/rvc-common/include/rvc-service-area-delegate.h @@ -35,39 +35,39 @@ class RvcServiceAreaDelegate : public Delegate { private: // containers for array attributes. - std::vector mSupportedLocations; + std::vector mSupportedAreas; std::vector mSupportedMaps; - std::vector mSelectedLocations; + std::vector mSelectedAreas; std::vector mProgressList; public: CHIP_ERROR Init() override; // command support - bool IsSetSelectedLocationsAllowed(MutableCharSpan statusText) override; + bool IsSetSelectedAreasAllowed(MutableCharSpan statusText) override; - bool IsValidSelectLocationsSet(const ServiceArea::Commands::SelectLocations::DecodableType & req, - ServiceArea::SelectLocationsStatus & locationStatus, MutableCharSpan statusText) override; + bool IsValidSelectAreasSet(const ServiceArea::Commands::SelectAreas::DecodableType & req, + ServiceArea::SelectAreasStatus & locationStatus, MutableCharSpan statusText) override; - bool HandleSkipCurrentLocation(MutableCharSpan skipStatusText) override; + bool HandleSkipCurrentArea(MutableCharSpan skipStatusText) override; //************************************************************************* // Supported Locations accessors - bool IsSupportedLocationsChangeAllowed() override; + bool IsSupportedAreasChangeAllowed() override; - uint32_t GetNumberOfSupportedLocations() override; + uint32_t GetNumberOfSupportedAreas() override; - bool GetSupportedLocationByIndex(uint32_t listIndex, ServiceArea::LocationStructureWrapper & supportedLocation) override; + bool GetSupportedLocationByIndex(uint32_t listIndex, ServiceArea::AreaStructureWrapper & supportedLocation) override; - bool GetSupportedLocationById(uint32_t aLocationId, uint32_t & listIndex, - ServiceArea::LocationStructureWrapper & supportedLocation) override; + bool GetSupportedLocationById(uint32_t aAreaId, uint32_t & listIndex, + ServiceArea::AreaStructureWrapper & supportedLocation) override; - bool AddSupportedLocation(const ServiceArea::LocationStructureWrapper & newLocation, uint32_t & listIndex) override; + bool AddSupportedLocation(const ServiceArea::AreaStructureWrapper & newArea, uint32_t & listIndex) override; - bool ModifySupportedLocation(uint32_t listIndex, const ServiceArea::LocationStructureWrapper & modifiedLocation) override; + bool ModifySupportedLocation(uint32_t listIndex, const ServiceArea::AreaStructureWrapper & modifiedLocation) override; - bool ClearSupportedLocations() override; + bool ClearSupportedAreas() override; //************************************************************************* // Supported Maps accessors @@ -89,15 +89,15 @@ class RvcServiceAreaDelegate : public Delegate //************************************************************************* // Selected Locations accessors - uint32_t GetNumberOfSelectedLocations() override; + uint32_t GetNumberOfSelectedAreas() override; bool GetSelectedLocationByIndex(uint32_t listIndex, uint32_t & selectedLocation) override; // IsSelectedLocation() no override - bool AddSelectedLocation(uint32_t aLocationId, uint32_t & listIndex) override; + bool AddSelectedLocation(uint32_t aAreaId, uint32_t & listIndex) override; - bool ClearSelectedLocations() override; + bool ClearSelectedAreas() override; //************************************************************************* // Progress accessors @@ -106,7 +106,7 @@ class RvcServiceAreaDelegate : public Delegate bool GetProgressElementByIndex(uint32_t listIndex, ServiceArea::Structs::ProgressStruct::Type & aProgressElement) override; - bool GetProgressElementById(uint32_t aLocationId, uint32_t & listIndex, + bool GetProgressElementById(uint32_t aAreaId, uint32_t & listIndex, ServiceArea::Structs::ProgressStruct::Type & aProgressElement) override; bool AddProgressElement(const ServiceArea::Structs::ProgressStruct::Type & newProgressElement, uint32_t & listIndex) override; diff --git a/examples/rvc-app/rvc-common/rvc-app.matter b/examples/rvc-app/rvc-common/rvc-app.matter index 56eebaae7cded7..7983c155e279e6 100644 --- a/examples/rvc-app/rvc-common/rvc-app.matter +++ b/examples/rvc-app/rvc-common/rvc-app.matter @@ -1421,17 +1421,17 @@ provisional cluster ServiceArea = 336 { kCompleted = 3; } - enum SelectLocationsStatus : enum8 { + enum SelectAreasStatus : enum8 { kSuccess = 0; - kUnsupportedLocation = 1; - kDuplicatedLocations = 2; + kUnsupportedArea = 1; + kDuplicatedAreas = 2; kInvalidInMode = 3; kInvalidSet = 4; } - enum SkipCurrentLocationStatus : enum8 { + enum SkipAreaStatus : enum8 { kSuccess = 0; - kInvalidLocationList = 1; + kInvalidAreaList = 1; kInvalidInMode = 2; } @@ -1440,17 +1440,17 @@ provisional cluster ServiceArea = 336 { kSelectWhileRunning = 0x2; } - struct LocationInfoStruct { + struct AreaInfoStruct { nullable LocationDescriptorStruct locationInfo = 0; nullable LandmarkTag landmarkTag = 1; nullable PositionTag positionTag = 2; nullable FloorSurfaceTag surfaceTag = 3; } - struct LocationStruct { - int32u locationID = 0; + struct AreaStruct { + int32u areaID = 0; nullable int8u mapID = 1; - LocationInfoStruct locationInfo = 2; + AreaInfoStruct areaDesc = 2; } struct MapStruct { @@ -1459,16 +1459,16 @@ provisional cluster ServiceArea = 336 { } struct ProgressStruct { - int32u locationID = 0; + int32u areaID = 0; OperationalStatusEnum status = 1; optional nullable elapsed_s totalOperationalTime = 2; optional nullable elapsed_s estimatedTime = 3; } - readonly attribute LocationStruct supportedLocations[] = 0; + readonly attribute AreaStruct supportedAreas[] = 0; readonly attribute nullable MapStruct supportedMaps[] = 1; - readonly attribute nullable int32u selectedLocations[] = 2; - readonly attribute optional nullable int32u currentLocation = 3; + readonly attribute nullable int32u selectedAreas[] = 2; + readonly attribute optional nullable int32u currentArea = 3; readonly attribute optional nullable epoch_s estimatedEndTime = 4; readonly attribute optional nullable ProgressStruct progress[] = 5; readonly attribute command_id generatedCommandList[] = 65528; @@ -1478,24 +1478,24 @@ provisional cluster ServiceArea = 336 { readonly attribute bitmap32 featureMap = 65532; readonly attribute int16u clusterRevision = 65533; - request struct SelectLocationsRequest { - nullable int32u newLocations[] = 0; + request struct SelectAreasRequest { + nullable int32u newAreas[] = 0; } - response struct SelectLocationsResponse = 1 { - SelectLocationsStatus status = 0; + response struct SelectAreasResponse = 1 { + SelectAreasStatus status = 0; optional char_string<256> statusText = 1; } - response struct SkipCurrentLocationResponse = 3 { - SkipCurrentLocationStatus status = 0; + response struct SkipAreaResponse = 3 { + SkipAreaStatus status = 0; optional char_string<256> statusText = 1; } - /** Command used to select a set of device locations, where the device is to operate */ - command SelectLocations(SelectLocationsRequest): SelectLocationsResponse = 0; - /** This command is used to skip the current location where the device operates. */ - command SkipCurrentLocation(): SkipCurrentLocationResponse = 2; + /** Command used to select a set of device areas, where the device is to operate. */ + command SelectAreas(SelectAreasRequest): SelectAreasResponse = 0; + /** This command is used to skip an area where the device operates. */ + command SkipArea(): SkipAreaResponse = 2; } endpoint 0 { @@ -1755,10 +1755,10 @@ endpoint 1 { } server cluster ServiceArea { - callback attribute supportedLocations; + callback attribute supportedAreas; callback attribute supportedMaps; - callback attribute selectedLocations; - callback attribute currentLocation; + callback attribute selectedAreas; + callback attribute currentArea; callback attribute estimatedEndTime; callback attribute progress; callback attribute generatedCommandList; @@ -1768,10 +1768,10 @@ endpoint 1 { callback attribute featureMap; ram attribute clusterRevision default = 1; - handle command SelectLocations; - handle command SelectLocationsResponse; - handle command SkipCurrentLocation; - handle command SkipCurrentLocationResponse; + handle command SelectAreas; + handle command SelectAreasResponse; + handle command SkipArea; + handle command SkipAreaResponse; } } diff --git a/examples/rvc-app/rvc-common/rvc-app.zap b/examples/rvc-app/rvc-common/rvc-app.zap index cb3ea7cc0d24c4..89fe82c64f5c21 100644 --- a/examples/rvc-app/rvc-common/rvc-app.zap +++ b/examples/rvc-app/rvc-common/rvc-app.zap @@ -2885,9 +2885,10 @@ "define": "SERVICE_AREA_CLUSTER", "side": "server", "enabled": 1, + "apiMaturity": "provisional", "commands": [ { - "name": "SelectLocations", + "name": "SelectAreas", "code": 0, "mfgCode": null, "source": "client", @@ -2895,7 +2896,7 @@ "isEnabled": 1 }, { - "name": "SelectLocationsResponse", + "name": "SelectAreasResponse", "code": 1, "mfgCode": null, "source": "server", @@ -2903,7 +2904,7 @@ "isEnabled": 1 }, { - "name": "SkipCurrent", + "name": "SkipArea", "code": 2, "mfgCode": null, "source": "client", @@ -2911,7 +2912,7 @@ "isEnabled": 1 }, { - "name": "SkipCurrentResponse", + "name": "SkipAreaResponse", "code": 3, "mfgCode": null, "source": "server", @@ -2921,7 +2922,7 @@ ], "attributes": [ { - "name": "SupportedLocations", + "name": "SupportedAreas", "code": 0, "mfgCode": null, "side": "server", @@ -2953,7 +2954,7 @@ "reportableChange": 0 }, { - "name": "SelectedLocations", + "name": "SelectedAreas", "code": 2, "mfgCode": null, "side": "server", @@ -2969,7 +2970,7 @@ "reportableChange": 0 }, { - "name": "CurrentLocation", + "name": "CurrentArea", "code": 3, "mfgCode": null, "side": "server", @@ -2978,7 +2979,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -2994,7 +2995,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3090,7 +3091,7 @@ "storageOption": "External", "singleton": 0, "bounded": 0, - "defaultValue": "0", + "defaultValue": null, "reportable": 1, "minInterval": 1, "maxInterval": 65534, diff --git a/examples/rvc-app/rvc-common/src/rvc-service-area-delegate.cpp b/examples/rvc-app/rvc-common/src/rvc-service-area-delegate.cpp index d913f53d83e940..977189032b3e27 100644 --- a/examples/rvc-app/rvc-common/src/rvc-service-area-delegate.cpp +++ b/examples/rvc-app/rvc-common/src/rvc-service-area-delegate.cpp @@ -32,25 +32,25 @@ CHIP_ERROR RvcServiceAreaDelegate::Init() GetInstance()->AddSupportedMap(supportedMapId_YY, "My Map YY"_span); // hardcoded fill of SUPPORTED LOCATIONS for prototyping - uint32_t supportedLocationId_A = 7; - uint32_t supportedLocationId_B = 1234567; - uint32_t supportedLocationId_C = 10050; - uint32_t supportedLocationId_D = 0x88888888; + uint32_t supportedAreaID_A = 7; + uint32_t supportedAreaID_B = 1234567; + uint32_t supportedAreaID_C = 10050; + uint32_t supportedAreaID_D = 0x88888888; // Location A has name, floor number, uses map XX GetInstance()->AddSupportedLocation( - supportedLocationId_A, DataModel::Nullable(supportedMapId_XX), "My Location A"_span, + supportedAreaID_A, DataModel::Nullable(supportedMapId_XX), "My Location A"_span, DataModel::Nullable(4), DataModel::Nullable(), DataModel::Nullable(), DataModel::Nullable(), DataModel::Nullable()); // Location B has name, uses map XX GetInstance()->AddSupportedLocation( - supportedLocationId_B, DataModel::Nullable(supportedMapId_XX), "My Location B"_span, + supportedAreaID_B, DataModel::Nullable(supportedMapId_XX), "My Location B"_span, DataModel::Nullable(), DataModel::Nullable(), DataModel::Nullable(), DataModel::Nullable(), DataModel::Nullable()); // Location C has full SemData, no name, Map YY - GetInstance()->AddSupportedLocation(supportedLocationId_C, DataModel::Nullable(supportedMapId_YY), CharSpan(), + GetInstance()->AddSupportedLocation(supportedAreaID_C, DataModel::Nullable(supportedMapId_YY), CharSpan(), DataModel::Nullable(-1), DataModel::Nullable(Globals::AreaTypeTag::kPlayRoom), DataModel::Nullable(Globals::LandmarkTag::kBackDoor), @@ -58,14 +58,14 @@ CHIP_ERROR RvcServiceAreaDelegate::Init() DataModel::Nullable(Globals::FloorSurfaceTag::kConcrete)); // Location D has null values for all HomeLocationStruct fields, Map YY - GetInstance()->AddSupportedLocation(supportedLocationId_D, DataModel::Nullable(supportedMapId_YY), + GetInstance()->AddSupportedLocation(supportedAreaID_D, DataModel::Nullable(supportedMapId_YY), "My Location D"_span, DataModel::Nullable(), DataModel::Nullable(), DataModel::Nullable(Globals::LandmarkTag::kCouch), DataModel::Nullable(Globals::PositionTag::kNextTo), DataModel::Nullable(Globals::FloorSurfaceTag::kHardwood)); - GetInstance()->SetCurrentLocation(supportedLocationId_C); + GetInstance()->SetCurrentArea(supportedAreaID_C); return CHIP_NO_ERROR; } @@ -73,20 +73,20 @@ CHIP_ERROR RvcServiceAreaDelegate::Init() //************************************************************************* // command support -bool RvcServiceAreaDelegate::IsSetSelectedLocationsAllowed(MutableCharSpan statusText) +bool RvcServiceAreaDelegate::IsSetSelectedAreasAllowed(MutableCharSpan statusText) { // TODO IMPLEMENT return true; }; -bool RvcServiceAreaDelegate::IsValidSelectLocationsSet(const Commands::SelectLocations::DecodableType & req, - SelectLocationsStatus & locationStatus, MutableCharSpan statusText) +bool RvcServiceAreaDelegate::IsValidSelectAreasSet(const Commands::SelectAreas::DecodableType & req, + SelectAreasStatus & locationStatus, MutableCharSpan statusText) { // TODO IMPLEMENT return true; }; -bool RvcServiceAreaDelegate::HandleSkipCurrentLocation(MutableCharSpan skipStatusText) +bool RvcServiceAreaDelegate::HandleSkipCurrentArea(MutableCharSpan skipStatusText) { // TODO IMPLEMENT return true; @@ -95,41 +95,41 @@ bool RvcServiceAreaDelegate::HandleSkipCurrentLocation(MutableCharSpan skipStatu //************************************************************************* // Supported Locations accessors -bool RvcServiceAreaDelegate::IsSupportedLocationsChangeAllowed() +bool RvcServiceAreaDelegate::IsSupportedAreasChangeAllowed() { // TODO IMPLEMENT return true; } -uint32_t RvcServiceAreaDelegate::GetNumberOfSupportedLocations() +uint32_t RvcServiceAreaDelegate::GetNumberOfSupportedAreas() { - return static_cast(mSupportedLocations.size()); + return static_cast(mSupportedAreas.size()); } -bool RvcServiceAreaDelegate::GetSupportedLocationByIndex(uint32_t listIndex, LocationStructureWrapper & aSupportedLocation) +bool RvcServiceAreaDelegate::GetSupportedLocationByIndex(uint32_t listIndex, AreaStructureWrapper & aSupportedLocation) { - if (listIndex < mSupportedLocations.size()) + if (listIndex < mSupportedAreas.size()) { - aSupportedLocation = mSupportedLocations[listIndex]; + aSupportedLocation = mSupportedAreas[listIndex]; return true; } return false; }; -bool RvcServiceAreaDelegate::GetSupportedLocationById(uint32_t aLocationId, uint32_t & listIndex, - LocationStructureWrapper & aSupportedLocation) +bool RvcServiceAreaDelegate::GetSupportedLocationById(uint32_t aAreaID, uint32_t & listIndex, + AreaStructureWrapper & aSupportedLocation) { // We do not need to reimplement this method as it's already done by the SDK. // We are reimplementing this method, still using linear search, but with some optimization on the SDK implementation // since we have direct access to the list. listIndex = 0; - while (listIndex < mSupportedLocations.size()) + while (listIndex < mSupportedAreas.size()) { - if (mSupportedLocations[listIndex].locationID == aLocationId) + if (mSupportedAreas[listIndex].areaID == aAreaID) { - aSupportedLocation = mSupportedLocations[listIndex]; + aSupportedLocation = mSupportedAreas[listIndex]; return true; } @@ -139,49 +139,49 @@ bool RvcServiceAreaDelegate::GetSupportedLocationById(uint32_t aLocationId, uint return false; }; -bool RvcServiceAreaDelegate::AddSupportedLocation(const LocationStructureWrapper & newLocation, uint32_t & listIndex) +bool RvcServiceAreaDelegate::AddSupportedLocation(const AreaStructureWrapper & newArea, uint32_t & listIndex) { - // The server instance (caller) is responsible for ensuring that there are no duplicate location IDs, list size not exceeded, + // The server instance (caller) is responsible for ensuring that there are no duplicate area IDs, list size not exceeded, // etc. // Double-check list size to ensure there no memory issues. - if (mSupportedLocations.size() < kMaxNumSupportedLocations) + if (mSupportedAreas.size() < kMaxNumSupportedAreas) { // not sorting list, number of locations normally expected to be small, max 255 - mSupportedLocations.push_back(newLocation); + mSupportedAreas.push_back(newArea); listIndex = static_cast(mSupportedMaps.size()) - 1; // new element is last in list return true; } - ChipLogError(Zcl, "AddSupportedLocation %u - supported locations list is already at maximum size %u", newLocation.locationID, - static_cast(kMaxNumSupportedLocations)); + ChipLogError(Zcl, "AddSupportedLocation %u - supported locations list is already at maximum size %u", newArea.areaID, + static_cast(kMaxNumSupportedAreas)); return false; } -bool RvcServiceAreaDelegate::ModifySupportedLocation(uint32_t listIndex, const LocationStructureWrapper & modifiedLocation) +bool RvcServiceAreaDelegate::ModifySupportedLocation(uint32_t listIndex, const AreaStructureWrapper & modifiedLocation) { - // The server instance (caller) is responsible for ensuring that there are no duplicate location IDs, list size not exceeded, + // The server instance (caller) is responsible for ensuring that there are no duplicate area IDs, list size not exceeded, // etc. - // Double-check that locationID's match. - if (modifiedLocation.locationID != mSupportedLocations[listIndex].locationID) + // Double-check that areaID's match. + if (modifiedLocation.areaID != mSupportedAreas[listIndex].areaID) { - ChipLogError(Zcl, "ModifySupportedLocation - locationID's do not match, new locationID %u, existing locationID %u", - modifiedLocation.locationID, mSupportedLocations[listIndex].locationID); + ChipLogError(Zcl, "ModifySupportedLocation - areaID's do not match, new areaID %u, existing areaID %u", + modifiedLocation.areaID, mSupportedAreas[listIndex].areaID); return false; } // checks passed, update the attribute - mSupportedLocations[listIndex] = modifiedLocation; + mSupportedAreas[listIndex] = modifiedLocation; return true; } -bool RvcServiceAreaDelegate::ClearSupportedLocations() +bool RvcServiceAreaDelegate::ClearSupportedAreas() { - if (!mSupportedLocations.empty()) + if (!mSupportedAreas.empty()) { - mSupportedLocations.clear(); + mSupportedAreas.clear(); return true; } @@ -236,7 +236,7 @@ bool RvcServiceAreaDelegate::GetSupportedMapById(uint8_t aMapId, uint32_t & list bool RvcServiceAreaDelegate::AddSupportedMap(const MapStructureWrapper & newMap, uint32_t & listIndex) { - // The server instance (caller) is responsible for ensuring that there are no duplicate location IDs, list size not exceeded, + // The server instance (caller) is responsible for ensuring that there are no duplicate area IDs, list size not exceeded, // etc. // Double-check list size to ensure there no memory issues. @@ -255,7 +255,7 @@ bool RvcServiceAreaDelegate::AddSupportedMap(const MapStructureWrapper & newMap, bool RvcServiceAreaDelegate::ModifySupportedMap(uint32_t listIndex, const MapStructureWrapper & modifiedMap) { - // The server instance (caller) is responsible for ensuring that there are no duplicate location IDs, list size not exceeded, + // The server instance (caller) is responsible for ensuring that there are no duplicate area IDs, list size not exceeded, // etc. // Double-check that mapID's match. @@ -285,46 +285,46 @@ bool RvcServiceAreaDelegate::ClearSupportedMaps() //************************************************************************* // Selected Locations accessors -uint32_t RvcServiceAreaDelegate::GetNumberOfSelectedLocations() +uint32_t RvcServiceAreaDelegate::GetNumberOfSelectedAreas() { - return static_cast(mSelectedLocations.size()); + return static_cast(mSelectedAreas.size()); } bool RvcServiceAreaDelegate::GetSelectedLocationByIndex(uint32_t listIndex, uint32_t & aSelectedLocation) { - if (listIndex < mSelectedLocations.size()) + if (listIndex < mSelectedAreas.size()) { - aSelectedLocation = mSelectedLocations[listIndex]; + aSelectedLocation = mSelectedAreas[listIndex]; return true; } return false; }; -bool RvcServiceAreaDelegate::AddSelectedLocation(uint32_t aLocationId, uint32_t & listIndex) +bool RvcServiceAreaDelegate::AddSelectedLocation(uint32_t aAreaID, uint32_t & listIndex) { - // The server instance (caller) is responsible for ensuring that there are no duplicate location IDs, list size not exceeded, + // The server instance (caller) is responsible for ensuring that there are no duplicate area IDs, list size not exceeded, // etc. // Double-check list size to ensure there no memory issues. - if (mSelectedLocations.size() < kMaxNumSelectedLocations) + if (mSelectedAreas.size() < kMaxNumSelectedAreas) { // not sorting list, number of locations normally expected to be small, max 255 - mSelectedLocations.push_back(aLocationId); - listIndex = static_cast(mSelectedLocations.size()) - 1; // new element is last in list + mSelectedAreas.push_back(aAreaID); + listIndex = static_cast(mSelectedAreas.size()) - 1; // new element is last in list return true; } - ChipLogError(Zcl, "AddSelectedLocation %u - selected locations list is already at maximum size %u", aLocationId, - static_cast(kMaxNumSelectedLocations)); + ChipLogError(Zcl, "AddSelectedLocation %u - selected locations list is already at maximum size %u", aAreaID, + static_cast(kMaxNumSelectedAreas)); return false; } -bool RvcServiceAreaDelegate::ClearSelectedLocations() +bool RvcServiceAreaDelegate::ClearSelectedAreas() { - if (!mSelectedLocations.empty()) + if (!mSelectedAreas.empty()) { - mSelectedLocations.clear(); + mSelectedAreas.clear(); return true; } @@ -350,7 +350,7 @@ bool RvcServiceAreaDelegate::GetProgressElementByIndex(uint32_t listIndex, Struc return false; }; -bool RvcServiceAreaDelegate::GetProgressElementById(uint32_t aLocationId, uint32_t & listIndex, +bool RvcServiceAreaDelegate::GetProgressElementById(uint32_t aAreaID, uint32_t & listIndex, Structs::ProgressStruct::Type & aProgressElement) { // We do not need to reimplement this method as it's already done by the SDK. @@ -360,7 +360,7 @@ bool RvcServiceAreaDelegate::GetProgressElementById(uint32_t aLocationId, uint32 while (listIndex < mProgressList.size()) { - if (mProgressList[listIndex].locationID == aLocationId) + if (mProgressList[listIndex].areaID == aAreaID) { aProgressElement = mProgressList[listIndex]; return true; @@ -374,7 +374,7 @@ bool RvcServiceAreaDelegate::GetProgressElementById(uint32_t aLocationId, uint32 bool RvcServiceAreaDelegate::AddProgressElement(const Structs::ProgressStruct::Type & newProgressElement, uint32_t & listIndex) { - // The server instance (caller) is responsible for ensuring that there are no duplicate location IDs, list size not exceeded, + // The server instance (caller) is responsible for ensuring that there are no duplicate area IDs, list size not exceeded, // etc. // Double-check list size to ensure there no memory issues. @@ -385,7 +385,7 @@ bool RvcServiceAreaDelegate::AddProgressElement(const Structs::ProgressStruct::T listIndex = static_cast(mProgressList.size()) - 1; // new element is last in list return true; } - ChipLogError(Zcl, "AddProgressElement %u -progress list is already at maximum size %u", newProgressElement.locationID, + ChipLogError(Zcl, "AddProgressElement %u -progress list is already at maximum size %u", newProgressElement.areaID, static_cast(kMaxNumProgressElements)); return false; diff --git a/src/app/clusters/service-area-server/service-area-cluster-objects.h b/src/app/clusters/service-area-server/service-area-cluster-objects.h index 1be2918795a1f0..4436a21e284a0f 100644 --- a/src/app/clusters/service-area-server/service-area-cluster-objects.h +++ b/src/app/clusters/service-area-server/service-area-cluster-objects.h @@ -31,12 +31,12 @@ inline constexpr size_t kLocationNameMaxSize = 128u; inline constexpr size_t kMapNameMaxSize = 64u; /** - * This class is used to wrap the LocationStruct object and provide a more user-friendly interface for the data. + * This class is used to wrap the AreaStruct object and provide a more user-friendly interface for the data. * It provides a way to store the location name in a buffer, and provides a way to compare the location name with a given string. */ -struct LocationStructureWrapper : public chip::app::Clusters::ServiceArea::Structs::LocationStruct::Type +struct AreaStructureWrapper : public chip::app::Clusters::ServiceArea::Structs::AreaStruct::Type { - LocationStructureWrapper() + AreaStructureWrapper() { Set(0, 0, CharSpan(), DataModel::Nullable(), DataModel::Nullable(), DataModel::Nullable(), DataModel::Nullable(), @@ -45,7 +45,7 @@ struct LocationStructureWrapper : public chip::app::Clusters::ServiceArea::Struc /** * @brief This is a full constructor that initializes the location object with the given values. All values are deep copied. - * @param[in] aLocationId The unique identifier of this location. + * @param[in] aAreaID The unique identifier of this location. * @param[in] aMapId The identifier of the supported map associated with this location. * @param[in] aLocationName A human readable name for this location (empty string if not used). * @param[in] aFloorNumber The floor level of this location - use negative values for below ground. @@ -60,14 +60,14 @@ struct LocationStructureWrapper : public chip::app::Clusters::ServiceArea::Struc * @note If aLocationName is larger than kLocationNameMaxSize, it will be truncated. * @note If aLocationName is an empty string and aFloorNumber and aAreaTypeTag are null, locationInfo will be set to null. */ - LocationStructureWrapper(uint32_t aLocationId, const DataModel::Nullable & aMapId, const CharSpan & aLocationName, - const DataModel::Nullable & aFloorNumber, - const DataModel::Nullable & aAreaTypeTag, - const DataModel::Nullable & aLandmarkTag, - const DataModel::Nullable & aPositionTag, - const DataModel::Nullable & aSurfaceTag) + AreaStructureWrapper(uint32_t aAreaID, const DataModel::Nullable & aMapId, const CharSpan & aLocationName, + const DataModel::Nullable & aFloorNumber, + const DataModel::Nullable & aAreaTypeTag, + const DataModel::Nullable & aLandmarkTag, + const DataModel::Nullable & aPositionTag, + const DataModel::Nullable & aSurfaceTag) { - Set(aLocationId, aMapId, aLocationName, aFloorNumber, aAreaTypeTag, aLandmarkTag, aPositionTag, aSurfaceTag); + Set(aAreaID, aMapId, aLocationName, aFloorNumber, aAreaTypeTag, aLandmarkTag, aPositionTag, aSurfaceTag); } /** @@ -77,7 +77,7 @@ struct LocationStructureWrapper : public chip::app::Clusters::ServiceArea::Struc * * @note If the locationName is empty string and aFloorNumber and aAreaTypeTag are null, locationInfo will be set to null. */ - LocationStructureWrapper(const LocationStructureWrapper & aOther) { *this = aOther; } + AreaStructureWrapper(const AreaStructureWrapper & aOther) { *this = aOther; } /** * @brief This is an assignment operator that initializes the location object with the values from another location object. All @@ -86,18 +86,18 @@ struct LocationStructureWrapper : public chip::app::Clusters::ServiceArea::Struc * * @note If the locationName is empty string and aFloorNumber and aAreaTypeTag are null, locationInfo will be set to null. */ - LocationStructureWrapper & operator=(const LocationStructureWrapper & aOther) + AreaStructureWrapper & operator=(const AreaStructureWrapper & aOther) { - if (aOther.locationInfo.locationInfo.IsNull()) + if (aOther.areaDesc.locationInfo.IsNull()) { - Set(aOther.locationID, aOther.mapID, CharSpan(), NullOptional, NullOptional, aOther.locationInfo.landmarkTag, - aOther.locationInfo.positionTag, aOther.locationInfo.surfaceTag); + Set(aOther.areaID, aOther.mapID, CharSpan(), NullOptional, NullOptional, aOther.areaDesc.landmarkTag, + aOther.areaDesc.positionTag, aOther.areaDesc.surfaceTag); } else { - Set(aOther.locationID, aOther.mapID, aOther.locationInfo.locationInfo.Value().locationName, - aOther.locationInfo.locationInfo.Value().floorNumber, aOther.locationInfo.locationInfo.Value().areaType, - aOther.locationInfo.landmarkTag, aOther.locationInfo.positionTag, aOther.locationInfo.surfaceTag); + Set(aOther.areaID, aOther.mapID, aOther.areaDesc.locationInfo.Value().locationName, + aOther.areaDesc.locationInfo.Value().floorNumber, aOther.areaDesc.locationInfo.Value().areaType, + aOther.areaDesc.landmarkTag, aOther.areaDesc.positionTag, aOther.areaDesc.surfaceTag); } return *this; @@ -105,7 +105,7 @@ struct LocationStructureWrapper : public chip::app::Clusters::ServiceArea::Struc /** * @brief Set all fields of the location object. All values are deep copied. - * @param[in] aLocationId The unique identifier of this location. + * @param[in] aAreaID The unique identifier of this location. * @param[in] aMapId The identifier of the supported map associated with this location. * @param[in] aLocationName A human readable name for this location (empty string if not used). * @param[in] aFloorNumber The floor level of this location - use negative values for below ground. @@ -120,51 +120,51 @@ struct LocationStructureWrapper : public chip::app::Clusters::ServiceArea::Struc * @note If aLocationName is larger than kLocationNameMaxSize, it will be truncated. * @note If aLocationName is an empty string and aFloorNumber and aAreaTypeTag are null, locationInfo will be set to null. */ - void Set(uint32_t aLocationId, const DataModel::Nullable & aMapId, const CharSpan & aLocationName, + void Set(uint32_t aAreaID, const DataModel::Nullable & aMapId, const CharSpan & aLocationName, const DataModel::Nullable & aFloorNumber, const DataModel::Nullable & aAreaType, const DataModel::Nullable & aLandmarkTag, const DataModel::Nullable & aPositionTag, const DataModel::Nullable & aSurfaceTag) { - locationID = aLocationId; - mapID = aMapId; + areaID = aAreaID; + mapID = aMapId; // If there is at least one non-null value for locationInfo, add it to the location structure. if ((!aLocationName.empty()) || (!aFloorNumber.IsNull()) || (!aAreaType.IsNull())) { - // Create a home location info structure and fill it in except for the location name. This is done below. - locationInfo.locationInfo.SetNonNull(Globals::Structs::LocationDescriptorStruct::Type()); + // Create a home location desc structure and fill it in except for the location name. This is done below. + areaDesc.locationInfo.SetNonNull(Globals::Structs::LocationDescriptorStruct::Type()); - locationInfo.locationInfo.Value().floorNumber = aFloorNumber; - locationInfo.locationInfo.Value().areaType = aAreaType; + areaDesc.locationInfo.Value().floorNumber = aFloorNumber; + areaDesc.locationInfo.Value().areaType = aAreaType; } else { - locationInfo.locationInfo.SetNull(); + areaDesc.locationInfo.SetNull(); } - locationInfo.landmarkTag = aLandmarkTag; - locationInfo.positionTag = aPositionTag; - locationInfo.surfaceTag = aSurfaceTag; + areaDesc.landmarkTag = aLandmarkTag; + areaDesc.positionTag = aPositionTag; + areaDesc.surfaceTag = aSurfaceTag; - // this assumes locationInfo structure was created above, if appropriate - if (!locationInfo.locationInfo.IsNull()) + // this assumes areaDesc structure was created above, if appropriate + if (!areaDesc.locationInfo.IsNull()) { if (aLocationName.empty()) { - locationInfo.locationInfo.Value().locationName = CharSpan(mLocationNameBuffer, 0); + areaDesc.locationInfo.Value().locationName = CharSpan(mLocationNameBuffer, 0); } else if (aLocationName.size() > sizeof(mLocationNameBuffer)) { // Save the truncated name that fits into available size. memcpy(mLocationNameBuffer, aLocationName.data(), sizeof(mLocationNameBuffer)); - locationInfo.locationInfo.Value().locationName = CharSpan(mLocationNameBuffer, sizeof(mLocationNameBuffer)); + areaDesc.locationInfo.Value().locationName = CharSpan(mLocationNameBuffer, sizeof(mLocationNameBuffer)); } else { // Save full name. memcpy(mLocationNameBuffer, aLocationName.data(), aLocationName.size()); - locationInfo.locationInfo.Value().locationName = CharSpan(mLocationNameBuffer, aLocationName.size()); + areaDesc.locationInfo.Value().locationName = CharSpan(mLocationNameBuffer, aLocationName.size()); } } } @@ -177,9 +177,9 @@ struct LocationStructureWrapper : public chip::app::Clusters::ServiceArea::Struc */ bool IsNameEqual(const CharSpan & aLocationName) const { - if (!locationInfo.locationInfo.IsNull()) + if (!areaDesc.locationInfo.IsNull()) { - return locationInfo.locationInfo.Value().locationName.data_equal(aLocationName); + return areaDesc.locationInfo.Value().locationName.data_equal(aLocationName); } return false; @@ -187,24 +187,24 @@ struct LocationStructureWrapper : public chip::app::Clusters::ServiceArea::Struc /** * This is used for configuring the IsEqual method. - * If kIgnoreLocationId is set, the location IDs are ignored when checking for equality. + * If kIgnoreAreaID is set, the area IDs are ignored when checking for equality. * If kIgnoreMapId is set, the map IDs are ignored when checking for equality. */ enum class IsEqualConfig : uint8_t { - kIgnoreLocationId = 0x1, - kIgnoreMapId = 0x2, + kIgnoreAreaID = 0x1, + kIgnoreMapId = 0x2, }; /** - * @brief Checks if the given LocationStructureWrapper is equal to this one. + * @brief Checks if the given AreaStructureWrapper is equal to this one. * @param aOther The location to compare with. - * @param aConfig Set if the location IDs and/or the map IDs should be ignored when checking for equality. + * @param aConfig Set if the area IDs and/or the map IDs should be ignored when checking for equality. * @return True if both locations are equal. False otherwise. */ - bool IsEqual(const LocationStructureWrapper & aOther, BitMask aConfig) const + bool IsEqual(const AreaStructureWrapper & aOther, BitMask aConfig) const { - if (!aConfig.Has(IsEqualConfig::kIgnoreLocationId) && (locationID != aOther.locationID)) + if (!aConfig.Has(IsEqualConfig::kIgnoreAreaID) && (areaID != aOther.areaID)) { return false; } @@ -214,41 +214,41 @@ struct LocationStructureWrapper : public chip::app::Clusters::ServiceArea::Struc return false; } - if (locationInfo.locationInfo.IsNull() != aOther.locationInfo.locationInfo.IsNull()) + if (areaDesc.locationInfo.IsNull() != aOther.areaDesc.locationInfo.IsNull()) { return false; } - if (!locationInfo.locationInfo.IsNull()) + if (!areaDesc.locationInfo.IsNull()) { - if (!IsNameEqual(aOther.locationInfo.locationInfo.Value().locationName)) + if (!IsNameEqual(aOther.areaDesc.locationInfo.Value().locationName)) { return false; } - if (locationInfo.locationInfo.Value().floorNumber != aOther.locationInfo.locationInfo.Value().floorNumber) + if (areaDesc.locationInfo.Value().floorNumber != aOther.areaDesc.locationInfo.Value().floorNumber) { return false; } - if (locationInfo.locationInfo.Value().areaType != aOther.locationInfo.locationInfo.Value().areaType) + if (areaDesc.locationInfo.Value().areaType != aOther.areaDesc.locationInfo.Value().areaType) { return false; } } - if (locationInfo.landmarkTag != aOther.locationInfo.landmarkTag) + if (areaDesc.landmarkTag != aOther.areaDesc.landmarkTag) { return false; } - if (locationInfo.positionTag != aOther.locationInfo.positionTag) + if (areaDesc.positionTag != aOther.areaDesc.positionTag) { return false; } - if (locationInfo.surfaceTag != aOther.locationInfo.surfaceTag) + if (areaDesc.surfaceTag != aOther.areaDesc.surfaceTag) { return false; } @@ -261,12 +261,12 @@ struct LocationStructureWrapper : public chip::app::Clusters::ServiceArea::Struc */ CharSpan GetName() { - if (locationInfo.locationInfo.IsNull()) + if (areaDesc.locationInfo.IsNull()) { return { mLocationNameBuffer, 0 }; } - return locationInfo.locationInfo.Value().locationName; + return areaDesc.locationInfo.Value().locationName; } private: diff --git a/src/app/clusters/service-area-server/service-area-delegate.cpp b/src/app/clusters/service-area-server/service-area-delegate.cpp index 1be7d257336c94..0d8c98a16f5d24 100644 --- a/src/app/clusters/service-area-server/service-area-delegate.cpp +++ b/src/app/clusters/service-area-server/service-area-delegate.cpp @@ -3,14 +3,14 @@ using namespace chip::app::Clusters::ServiceArea; -bool Delegate::GetSupportedLocationById(uint32_t aLocationId, uint32_t & listIndex, LocationStructureWrapper & aSupportedLocation) +bool Delegate::GetSupportedLocationById(uint32_t aAreaId, uint32_t & listIndex, AreaStructureWrapper & aSupportedLocation) { listIndex = 0; - // simple linear iteration to find the location with the desired locationID. + // simple linear iteration to find the location with the desired areaId. while (GetSupportedLocationByIndex(listIndex, aSupportedLocation)) { - if (aSupportedLocation.locationID == aLocationId) + if (aSupportedLocation.areaID == aAreaId) { return true; } @@ -21,10 +21,10 @@ bool Delegate::GetSupportedLocationById(uint32_t aLocationId, uint32_t & listInd return false; } -void Delegate::HandleSupportedLocationsUpdated() +void Delegate::HandleSupportedAreasUpdated() { - mInstance->ClearSelectedLocations(); - mInstance->SetCurrentLocation(DataModel::NullNullable); + mInstance->ClearSelectedAreas(); + mInstance->SetCurrentArea(DataModel::NullNullable); mInstance->ClearProgress(); } @@ -45,14 +45,14 @@ bool Delegate::GetSupportedMapById(uint8_t aMapId, uint32_t & listIndex, MapStru return false; } -bool Delegate::IsSelectedLocation(uint32_t aLocationId) +bool Delegate::IsSelectedLocation(uint32_t aAreaId) { uint32_t listIndex = 0; uint32_t selectedLocation; while (GetSelectedLocationByIndex(listIndex, selectedLocation)) { - if (selectedLocation == aLocationId) + if (selectedLocation == aAreaId) { return true; } @@ -63,14 +63,14 @@ bool Delegate::IsSelectedLocation(uint32_t aLocationId) return false; } -bool Delegate::GetProgressElementById(uint32_t aLocationId, uint32_t & listIndex, Structs::ProgressStruct::Type & aProgressElement) +bool Delegate::GetProgressElementById(uint32_t aAreaId, uint32_t & listIndex, Structs::ProgressStruct::Type & aProgressElement) { listIndex = 0; - // simple linear iteration to find the progress element with the desired locationID. + // simple linear iteration to find the progress element with the desired areaID. while (GetProgressElementByIndex(listIndex, aProgressElement)) { - if (aProgressElement.locationID == aLocationId) + if (aProgressElement.areaID == aAreaId) { return true; } @@ -81,10 +81,10 @@ bool Delegate::GetProgressElementById(uint32_t aLocationId, uint32_t & listIndex return false; } -bool Delegate::IsProgressElement(uint32_t aLocationId) +bool Delegate::IsProgressElement(uint32_t aAreaId) { uint32_t index; Structs::ProgressStruct::Type progressElement; - return GetProgressElementById(aLocationId, index, progressElement); + return GetProgressElementById(aAreaId, index, progressElement); } diff --git a/src/app/clusters/service-area-server/service-area-delegate.h b/src/app/clusters/service-area-server/service-area-delegate.h index baf50d071b3404..1c324fe2c70bc7 100644 --- a/src/app/clusters/service-area-server/service-area-delegate.h +++ b/src/app/clusters/service-area-server/service-area-delegate.h @@ -31,10 +31,10 @@ class Instance; // ***************************************************************************** // cluster constraints -constexpr size_t kMaxNumSupportedLocations = 255; -constexpr size_t kMaxNumSupportedMaps = 255; -constexpr size_t kMaxNumSelectedLocations = 255; -constexpr size_t kMaxNumProgressElements = 255; +constexpr size_t kMaxNumSupportedAreas = 255; +constexpr size_t kMaxNumSupportedMaps = 255; +constexpr size_t kMaxNumSelectedAreas = 255; +constexpr size_t kMaxNumProgressElements = 255; constexpr size_t kMaxSizeStatusText = 256; @@ -71,10 +71,10 @@ class Delegate * @note The statusText field SHOULD indicate why the request is not allowed, given the current mode * of the device, which may involve other clusters. */ - virtual bool IsSetSelectedLocationsAllowed(MutableCharSpan statusText) = 0; + virtual bool IsSetSelectedAreasAllowed(MutableCharSpan statusText) = 0; /** - * Given a set of locations to be set to the SelectedLocations attribute, this method should check that + * Given a set of locations to be set to the SelectedAreas attribute, this method should check that * the set of locations as a whole is valid and reachable by the device. * If the set of locations is invalid, the locationStatus should be set to InvalidSet and * the statusText SHALL include a vendor-defined error description. @@ -87,14 +87,14 @@ class Delegate * @param[out] statusText text describing failure (see description above), size kMaxSizeStatusText. * @return true if success. * - * @note If the SelectLocations command is allowed when the device is operating and the selected locations change to none, the + * @note If the SelectAreas command is allowed when the device is operating and the selected locations change to none, the * device must stop. */ - virtual bool IsValidSelectLocationsSet(const Commands::SelectLocations::DecodableType & req, - SelectLocationsStatus & locationStatus, MutableCharSpan statusText) = 0; + virtual bool IsValidSelectAreasSet(const Commands::SelectAreas::DecodableType & req, SelectAreasStatus & locationStatus, + MutableCharSpan statusText) = 0; /** - * @brief The server instance ensures that the SelectedLocations and CurrentLocation attributes are not null before + * @brief The server instance ensures that the SelectedAreas and CurrentArea attributes are not null before * calling this method. * @param[out] skipStatusText text describing why current location cannot be skipped. * @return true if command is successful, false if the received skip request cannot be handled due to the current mode of the @@ -104,13 +104,13 @@ class Delegate * * @note If the device successfully accepts the request and the ListOrder feature is set to 1: * The server SHALL stop operating at the current location. - * The server SHALL attempt to operate at the remaining locations on the SelectedLocations attribute list, starting with - * the next entry. If the end of the SelectedLocations attribute list is reached, the server SHALL stop operating. + * The server SHALL attempt to operate at the remaining locations on the SelectedAreas attribute list, starting with + * the next entry. If the end of the SelectedAreas attribute list is reached, the server SHALL stop operating. * * @note If the device successfully accepts the request and the ListOrder feature is set to 0: * The server SHALL stop operating at the current location. - * The server SHALL attempt to operate at the locations on the SelectedLocations attribute list where operating has not - * been completed, using a vendor defined order. If the server has completed operating at all locations on the SelectedLocations + * The server SHALL attempt to operate at the locations on the SelectedAreas attribute list where operating has not + * been completed, using a vendor defined order. If the server has completed operating at all locations on the SelectedAreas * attribute list, the server SHALL stop operating. * * @note If the Status field is set to InvalidLocationList, the StatusText field SHALL be an empty string. @@ -119,7 +119,7 @@ class Delegate * InvalidInMode, the StatusText field SHOULD indicate why the request is not allowed, given the current mode of the device, * which may involve other clusters. */ - virtual bool HandleSkipCurrentLocation(MutableCharSpan skipStatusText) + virtual bool HandleSkipCurrentArea(MutableCharSpan skipStatusText) { // device support of this command is optional CopyCharSpanToMutableCharSpan("Skip Current Location command not supported by device"_span, skipStatusText); @@ -127,23 +127,23 @@ class Delegate } //************************************************************************* - // Supported Locations accessors + // Supported Areas accessors /** - * @return true if the current device state allows the SupportedLocations attribute to be updated. + * @return true if the current device state allows the SupportedAreas attribute to be updated. * - * @note The SupportedLocations attribute list changes (adding or deleting entries, - * changing their MapID fields, changing the LocationID fields, or nulling the entire list) + * @note The SupportedAreas attribute list changes (adding or deleting entries, + * changing their MapID fields, changing the AreaID fields, or nulling the entire list) * SHOULD NOT be allowed while the device is operating, to reduce the impact on the clients, * and the potential confusion for the users. * * @note The device implementation MAY allow supported location changes while operating if the device - * repopulates the SupportedMaps, SupportedLocations, CurrentLocation, and Progress attributes with + * repopulates the SupportedMaps, SupportedAreas, CurrentArea, and Progress attributes with * data matching the constraints listed in the requirements for each attribute. */ - virtual bool IsSupportedLocationsChangeAllowed() = 0; + virtual bool IsSupportedAreasChangeAllowed() = 0; - virtual uint32_t GetNumberOfSupportedLocations() = 0; + virtual uint32_t GetNumberOfSupportedAreas() = 0; /** * @brief Get a supported location using the position in the list. @@ -151,30 +151,29 @@ class Delegate * @param[out] aSupportedLocation copy of the location contents, if found. * @return true if location found, false otherwise. */ - virtual bool GetSupportedLocationByIndex(uint32_t listIndex, LocationStructureWrapper & aSupportedLocation) = 0; + virtual bool GetSupportedLocationByIndex(uint32_t listIndex, AreaStructureWrapper & aSupportedLocation) = 0; /** - * @brief Get a supported location that matches a locationID. - * @param[in] aLocationId the locationID to search for. + * @brief Get a supported location that matches a areaID. + * @param[in] aAreaId the areaID to search for. * @param[out] listIndex the location's index in the list, if found. * @param[out] aSupportedLocation copy of the location contents, if found. * @return true if location found, false otherwise. * * @note may be overloaded in device implementation for optimization, if desired. */ - virtual bool GetSupportedLocationById(uint32_t aLocationId, uint32_t & listIndex, - LocationStructureWrapper & aSupportedLocation); + virtual bool GetSupportedLocationById(uint32_t aAreaId, uint32_t & listIndex, AreaStructureWrapper & aSupportedLocation); /** * This method is called by the server instance to add a new location to the list. - * The server instance will ensure that the newLocation is a valid, unique location. - * @param [in] newLocation new location to add. + * The server instance will ensure that the newArea is a valid, unique location. + * @param [in] newArea new location to add. * @param [out] listIndex filled with the list index for the new location, if successful. * @return true if successful, false otherwise. * @note this function SHOULD double check that the added location won't exceed the maximum list size. */ - virtual bool AddSupportedLocation(const LocationStructureWrapper & newLocation, uint32_t & listIndex) = 0; + virtual bool AddSupportedLocation(const AreaStructureWrapper & newArea, uint32_t & listIndex) = 0; /** * This method is called by the server instance to modify an existing location in the list. @@ -183,31 +182,31 @@ class Delegate * @param[in] modifiedLocation A location with the modified contents. * @return true if successful, false otherwise. * - * @note this function SHOULD double check that newLocation's locationID matches the object at listIndex. + * @note this function SHOULD double check that newArea's areaID matches the object at listIndex. */ - virtual bool ModifySupportedLocation(uint32_t listIndex, const LocationStructureWrapper & modifiedLocation) = 0; + virtual bool ModifySupportedLocation(uint32_t listIndex, const AreaStructureWrapper & modifiedLocation) = 0; /** * @return true if supported locations was not already null, false otherwise. */ - virtual bool ClearSupportedLocations() = 0; + virtual bool ClearSupportedAreas() = 0; /** - * @brief Ensure that when the Supported locations is modified, the required restrictions for the SelectedLocations, - * CurrentLocation, and Progress attributes are maintained. + * @brief Ensure that when the Supported locations is modified, the required restrictions for the SelectedAreas, + * CurrentArea, and Progress attributes are maintained. * * This method will be called by the SDK whenever the adherence to the restrictions for these attributes cannot be guaranteed. - * For example, if there are deletions in the SupportedMops or SupportedLocations attributes, or if there are changes to their - * IDs. This method will no be called if the changes made to the SupportedMops or SupportedLocations attributes, ensure that the + * For example, if there are deletions in the SupportedMops or SupportedAreas attributes, or if there are changes to their + * IDs. This method will no be called if the changes made to the SupportedMops or SupportedAreas attributes, ensure that the * restrictions are adhered. For example, if there are additions or the modifications do not involve changing IDs in the - * SupportedMops or SupportedLocations attributes. + * SupportedMops or SupportedAreas attributes. * - * The default implementation will set the SelectedLocations, CurrentLocation, and Progress attributes to null. + * The default implementation will set the SelectedAreas, CurrentArea, and Progress attributes to null. * * The user is free the redefine this method as their device may have more information on what has changed and may be able to * maintain the restrictions on these attributes by selectively editing them. */ - virtual void HandleSupportedLocationsUpdated(); + virtual void HandleSupportedAreasUpdated(); //************************************************************************* // Supported Maps accessors @@ -221,7 +220,7 @@ class Delegate * and the potential confusion for the users. * * @note The device implementation MAY allow supported maps changes while operating if the device - * repopulates the SupportedLocations, CurrentLocation, and Progress attributes with + * repopulates the SupportedAreas, CurrentArea, and Progress attributes with * data matching the constraints listed in the requirements for each attribute. */ virtual bool IsSupportedMapChangeAllowed() = 0; @@ -277,7 +276,7 @@ class Delegate //************************************************************************* // Selected Locations accessors - virtual uint32_t GetNumberOfSelectedLocations() = 0; + virtual uint32_t GetNumberOfSelectedAreas() = 0; /** * @brief Get a selected location using the position in the list. @@ -288,28 +287,28 @@ class Delegate virtual bool GetSelectedLocationByIndex(uint32_t listIndex, uint32_t & selectedLocation) = 0; /** - * @return true if the aLocationId locationID is found in the SelectedLocations list, false otherwise. + * @return true if the aAreaId areaID is found in the SelectedAreas list, false otherwise. * * @note may be overloaded in device implementation for optimization, if desired. */ - virtual bool IsSelectedLocation(uint32_t aLocationId); + virtual bool IsSelectedLocation(uint32_t aAreaId); /** * This method is called by the server instance to add a new selected location to the list. - * The server instance will ensure that the aLocationId references a SUPPORTED location, and is unique within selected + * The server instance will ensure that the aAreaId references a SUPPORTED location, and is unique within selected * locations. - * @param[in] aLocationId The new locationID to add. + * @param[in] aAreaId The new areaID to add. * @param[out] listIndex filled with the list index of the new location, if successful. * @return true if successful, false otherwise. * * @note this function SHOULD double check that the added location won't exceed the maximum list size. */ - virtual bool AddSelectedLocation(uint32_t aLocationId, uint32_t & listIndex) = 0; + virtual bool AddSelectedLocation(uint32_t aAreaId, uint32_t & listIndex) = 0; /** * @return true if selected locations was not already null, false otherwise. */ - virtual bool ClearSelectedLocations() = 0; + virtual bool ClearSelectedAreas() = 0; //************************************************************************* // Progress accessors @@ -325,23 +324,22 @@ class Delegate virtual bool GetProgressElementByIndex(uint32_t listIndex, Structs::ProgressStruct::Type & aProgressElement) = 0; /** - * @brief Get a progress element that matches a locationID. - * @param[in] aLocationId the locationID to search for. + * @brief Get a progress element that matches a areaID. + * @param[in] aAreaId the areaID to search for. * @param[out] listIndex the location's index in the list, if found. * @param[out] aProgressElement copy of the progress element contents, if found. * @return true if a progress element is found, false otherwise. * * @note may be overloaded in device implementation for optimization, if desired. */ - virtual bool GetProgressElementById(uint32_t aLocationId, uint32_t & listIndex, - Structs::ProgressStruct::Type & aProgressElement); + virtual bool GetProgressElementById(uint32_t aAreaId, uint32_t & listIndex, Structs::ProgressStruct::Type & aProgressElement); /** * @brief Is the progress element in the progress list? - * @param[in] aLocationId location id of the progress element. + * @param[in] aAreaId location id of the progress element. * @return true if the progress element identified by Id is in the progress list. */ - virtual bool IsProgressElement(uint32_t aLocationId); + virtual bool IsProgressElement(uint32_t aAreaId); /** * This method is called by the server instance to add a new progress element to the list. @@ -361,7 +359,7 @@ class Delegate * @param[in] modifiedProgressElement modified element's contents. * @return true if successful, false otherwise. * - * @note this function SHOULD double check that modifiedProgressElement's locationID matches the object at listIndex + * @note this function SHOULD double check that modifiedProgressElement's areaID matches the object at listIndex */ virtual bool ModifyProgressElement(uint32_t listIndex, const Structs::ProgressStruct::Type & modifiedProgressElement) = 0; diff --git a/src/app/clusters/service-area-server/service-area-server.cpp b/src/app/clusters/service-area-server/service-area-server.cpp index 79837ff0bf216c..66556acd03ea0b 100644 --- a/src/app/clusters/service-area-server/service-area-server.cpp +++ b/src/app/clusters/service-area-server/service-area-server.cpp @@ -85,17 +85,17 @@ CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValu switch (aPath.mAttributeId) { - case Attributes::SupportedLocations::Id: - return ReadSupportedLocations(aEncoder); + case Attributes::SupportedAreas::Id: + return ReadSupportedAreas(aEncoder); case Attributes::SupportedMaps::Id: return ReadSupportedMaps(aEncoder); - case Attributes::SelectedLocations::Id: - return ReadSelectedLocations(aEncoder); + case Attributes::SelectedAreas::Id: + return ReadSelectedAreas(aEncoder); - case Attributes::CurrentLocation::Id: - return aEncoder.Encode(GetCurrentLocation()); + case Attributes::CurrentArea::Id: + return aEncoder.Encode(GetCurrentArea()); case Attributes::EstimatedEndTime::Id: return aEncoder.Encode(GetEstimatedEndTime()); @@ -117,29 +117,29 @@ void Instance::InvokeCommand(HandlerContext & handlerContext) { switch (handlerContext.mRequestPath.mCommandId) { - case Commands::SelectLocations::Id: - return CommandHandlerInterface::HandleCommand( - handlerContext, [this](HandlerContext & ctx, const auto & req) { HandleSelectLocationsCmd(ctx, req); }); + case Commands::SelectAreas::Id: + return CommandHandlerInterface::HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & req) { HandleSelectAreasCmd(ctx, req); }); - case Commands::SkipCurrentLocation::Id: - return CommandHandlerInterface::HandleCommand( - handlerContext, [this](HandlerContext & ctx, const auto & req) { HandleSkipCurrentLocationCmd(ctx); }); + case Commands::SkipArea::Id: + return CommandHandlerInterface::HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & req) { HandleSkipCurrentAreaCmd(ctx); }); } } //************************************************************************* // attribute readers -CHIP_ERROR Instance::ReadSupportedLocations(AttributeValueEncoder & aEncoder) +CHIP_ERROR Instance::ReadSupportedAreas(AttributeValueEncoder & aEncoder) { - if (mDelegate->GetNumberOfSupportedLocations() == 0) + if (mDelegate->GetNumberOfSupportedAreas() == 0) { return aEncoder.EncodeNull(); } return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { uint8_t locationIndex = 0; - LocationStructureWrapper supportedLocation; + AreaStructureWrapper supportedLocation; while (mDelegate->GetSupportedLocationByIndex(locationIndex++, supportedLocation)) { @@ -168,9 +168,9 @@ CHIP_ERROR Instance::ReadSupportedMaps(AttributeValueEncoder & aEncoder) }); } -CHIP_ERROR Instance::ReadSelectedLocations(AttributeValueEncoder & aEncoder) +CHIP_ERROR Instance::ReadSelectedAreas(AttributeValueEncoder & aEncoder) { - if (mDelegate->GetNumberOfSelectedLocations() == 0) + if (mDelegate->GetNumberOfSelectedAreas() == 0) { return aEncoder.EncodeNull(); } @@ -209,13 +209,13 @@ CHIP_ERROR Instance::ReadProgress(AttributeValueEncoder & aEncoder) //************************************************************************* // command handlers -void Instance::HandleSelectLocationsCmd(HandlerContext & ctx, const Commands::SelectLocations::DecodableType & req) +void Instance::HandleSelectAreasCmd(HandlerContext & ctx, const Commands::SelectAreas::DecodableType & req) { - ChipLogDetail(Zcl, "Service Area: HandleSelectLocationsCmd"); + ChipLogDetail(Zcl, "Service Area: HandleSelectAreasCmd"); - // On receipt of this command the device SHALL respond with a SelectLocationsResponse command. - auto exitResponse = [ctx](SelectLocationsStatus status, CharSpan statusText) { - Commands::SelectLocationsResponse::Type response{ + // On receipt of this command the device SHALL respond with a SelectAreasResponse command. + auto exitResponse = [ctx](SelectAreasStatus status, CharSpan statusText) { + Commands::SelectAreasResponse::Type response{ .status = status, .statusText = Optional(statusText), }; @@ -224,68 +224,68 @@ void Instance::HandleSelectLocationsCmd(HandlerContext & ctx, const Commands::Se size_t numberOfLocations = 0; // Get the number of Selected Locations in the command parameter and check that it is valid. - if (!req.newLocations.IsNull()) + if (!req.newAreas.IsNull()) { - if (CHIP_NO_ERROR != req.newLocations.Value().ComputeSize(&numberOfLocations)) + if (CHIP_NO_ERROR != req.newAreas.Value().ComputeSize(&numberOfLocations)) { ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); return; } // If the device determines that it can't operate at all locations from the list, - // the SelectLocationsResponse command's Status field SHALL indicate InvalidSet. - if (numberOfLocations > kMaxNumSelectedLocations) + // the SelectAreasResponse command's Status field SHALL indicate InvalidSet. + if (numberOfLocations > kMaxNumSelectedAreas) { - exitResponse(SelectLocationsStatus::kInvalidSet, "invalid number of locations"_span); + exitResponse(SelectAreasStatus::kInvalidSet, "invalid number of locations"_span); return; } } // if number of selected locations in parameter matches number in attribute - the locations *might* be the same - bool matchesCurrentSelectedLocations = (numberOfLocations == mDelegate->GetNumberOfSelectedLocations()); + bool matchesCurrentSelectedAreas = (numberOfLocations == mDelegate->GetNumberOfSelectedAreas()); - if (!req.newLocations.IsNull()) + if (!req.newAreas.IsNull()) { // do as much parameter validation as we can { uint32_t ignoredIndex = 0; uint32_t oldSelectedLocation; uint32_t i = 0; - auto iLocationIter = req.newLocations.Value().begin(); + auto iLocationIter = req.newAreas.Value().begin(); while (iLocationIter.Next()) { uint32_t aSelectedLocation = iLocationIter.GetValue(); - // each item in this list SHALL match the LocationID field of an entry on the SupportedLocations attribute's list + // each item in this list SHALL match the AreaID field of an entry on the SupportedAreas attribute's list // If the Status field is set to UnsupportedLocation, the StatusText field SHALL be an empty string. if (!IsSupportedLocation(aSelectedLocation)) { - exitResponse(SelectLocationsStatus::kUnsupportedLocation, ""_span); + exitResponse(SelectAreasStatus::kUnsupportedArea, ""_span); return; } // Checking for duplicate locations. uint32_t j = 0; - auto jLocationIter = req.newLocations.Value().begin(); + auto jLocationIter = req.newAreas.Value().begin(); while (j < i) { jLocationIter .Next(); // Since j < i and i is valid, we can safely call Next() without checking the return value. if (jLocationIter.GetValue() == aSelectedLocation) { - exitResponse(SelectLocationsStatus::kDuplicatedLocations, ""_span); + exitResponse(SelectAreasStatus::kDuplicatedAreas, ""_span); return; } j += 1; } // check to see if parameter list and attribute still match - if (matchesCurrentSelectedLocations) + if (matchesCurrentSelectedAreas) { if (!mDelegate->GetSelectedLocationByIndex(ignoredIndex, oldSelectedLocation) || (aSelectedLocation != oldSelectedLocation)) { - matchesCurrentSelectedLocations = false; + matchesCurrentSelectedAreas = false; } } @@ -301,12 +301,12 @@ void Instance::HandleSelectLocationsCmd(HandlerContext & ctx, const Commands::Se } } - // If the NewLocations field is the same as the value of the SelectedLocations attribute - // the SelectLocationsResponse command SHALL have the Status field set to Success and + // If the newAreas field is the same as the value of the SelectedAreas attribute + // the SelectAreasResponse command SHALL have the Status field set to Success and // the StatusText field MAY be supplied with a human-readable string or include an empty string. - if (matchesCurrentSelectedLocations) + if (matchesCurrentSelectedAreas) { - exitResponse(SelectLocationsStatus::kSuccess, ""_span); + exitResponse(SelectAreasStatus::kSuccess, ""_span); return; } @@ -314,23 +314,23 @@ void Instance::HandleSelectLocationsCmd(HandlerContext & ctx, const Commands::Se MutableCharSpan delegateStatusText(delegateStatusBuffer); // If the current state of the device doesn't allow for the locations to be selected, - // the SelectLocationsResponse command SHALL have the Status field set to InvalidInMode. + // the SelectAreasResponse command SHALL have the Status field set to InvalidInMode. // if the Status field is set to InvalidInMode, the StatusText field SHOULD indicate why the request is not allowed, // given the current mode of the device, which may involve other clusters. // (note - locationStatusText to be filled out by delegated function for if return value is false) - if (!mDelegate->IsSetSelectedLocationsAllowed(delegateStatusText)) + if (!mDelegate->IsSetSelectedAreasAllowed(delegateStatusText)) { - exitResponse(SelectLocationsStatus::kInvalidInMode, delegateStatusText); + exitResponse(SelectAreasStatus::kInvalidInMode, delegateStatusText); return; } // Reset in case the delegate accidentally modified this string. delegateStatusText = MutableCharSpan(delegateStatusBuffer); - // ask the device to handle SelectLocations Command + // ask the device to handle SelectAreas Command // (note - locationStatusText to be filled out by delegated function for kInvalidInMode and InvalidSet) - auto locationStatus = SelectLocationsStatus::kSuccess; - if (!mDelegate->IsValidSelectLocationsSet(req, locationStatus, delegateStatusText)) + auto locationStatus = SelectAreasStatus::kSuccess; + if (!mDelegate->IsValidSelectAreasSet(req, locationStatus, delegateStatusText)) { exitResponse(locationStatus, delegateStatusText); return; @@ -338,14 +338,14 @@ void Instance::HandleSelectLocationsCmd(HandlerContext & ctx, const Commands::Se { // If the device successfully accepts the request, the server will attempt to operate at the location(s) - // indicated by the entries of the NewLocation field, when requested to operate, - // the SelectLocationsResponse command SHALL have the Status field set to Success, - // and the SelectedLocations attribute SHALL be set to the value of the NewLocations field. - mDelegate->ClearSelectedLocations(); + // indicated by the entries of the newArea field, when requested to operate, + // the SelectAreasResponse command SHALL have the Status field set to Success, + // and the SelectedAreas attribute SHALL be set to the value of the newAreas field. + mDelegate->ClearSelectedAreas(); - if (!req.newLocations.IsNull()) + if (!req.newAreas.IsNull()) { - auto locationIter = req.newLocations.Value().begin(); + auto locationIter = req.newAreas.Value().begin(); uint32_t ignored; while (locationIter.Next()) { @@ -353,40 +353,40 @@ void Instance::HandleSelectLocationsCmd(HandlerContext & ctx, const Commands::Se } } - NotifySelectedLocationsChanged(); + NotifySelectedAreasChanged(); } - exitResponse(SelectLocationsStatus::kSuccess, ""_span); + exitResponse(SelectAreasStatus::kSuccess, ""_span); } -void Instance::HandleSkipCurrentLocationCmd(HandlerContext & ctx) +void Instance::HandleSkipCurrentAreaCmd(HandlerContext & ctx) { - ChipLogDetail(Zcl, "Service Area: HandleSkipCurrentLocation"); + ChipLogDetail(Zcl, "Service Area: HandleSkipCurrentArea"); - // On receipt of this command the device SHALL respond with a SkipCurrentLocationResponse command. - auto exitResponse = [ctx](SkipCurrentLocationStatus status, CharSpan statusText) { - Commands::SkipCurrentLocationResponse::Type response{ + // On receipt of this command the device SHALL respond with a SkipCurrentAreaResponse command. + auto exitResponse = [ctx](SkipAreaStatus status, CharSpan statusText) { + Commands::SkipAreaResponse::Type response{ .status = status, .statusText = Optional(statusText), }; ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); }; - // If the SelectedLocations attribute is null, the response status should be set to InvalidLocationList. + // If the SelectedAreas attribute is null, the response status should be set to InvalidLocationList. // If the Status field is set to InvalidLocationList, the StatusText field SHALL be an empty string. - if (mDelegate->GetNumberOfSelectedLocations() == 0) + if (mDelegate->GetNumberOfSelectedAreas() == 0) { ChipLogError(Zcl, "Selected Locations attribute is null"); - exitResponse(SkipCurrentLocationStatus::kInvalidLocationList, ""_span); + exitResponse(SkipAreaStatus::kInvalidAreaList, ""_span); return; } - // If the CurrentLocation attribute is null, the status should be set to InvalidInMode. + // If the CurrentArea attribute is null, the status should be set to InvalidInMode. // If the Status field is not set to Success, or InvalidLocationList, the StatusText field SHALL include a vendor defined error // description. - if (mCurrentLocation.IsNull()) + if (mCurrentArea.IsNull()) { - exitResponse(SkipCurrentLocationStatus::kInvalidInMode, "Current Location attribute is null"_span); + exitResponse(SkipAreaStatus::kInvalidInMode, "Current Location attribute is null"_span); return; } @@ -397,9 +397,9 @@ void Instance::HandleSkipCurrentLocationCmd(HandlerContext & ctx) char skipStatusBuffer[kMaxSizeStatusText]; MutableCharSpan skipStatusText(skipStatusBuffer); - if (!mDelegate->HandleSkipCurrentLocation(skipStatusText)) + if (!mDelegate->HandleSkipCurrentArea(skipStatusText)) { - exitResponse(SkipCurrentLocationStatus::kInvalidInMode, skipStatusText); + exitResponse(SkipAreaStatus::kInvalidInMode, skipStatusText); return; } } @@ -407,9 +407,9 @@ void Instance::HandleSkipCurrentLocationCmd(HandlerContext & ctx) //************************************************************************* // attribute notifications -void Instance::NotifySupportedLocationsChanged() +void Instance::NotifySupportedAreasChanged() { - MatterReportingAttributeChangeCallback(mEndpointId, mClusterId, Attributes::SupportedLocations::Id); + MatterReportingAttributeChangeCallback(mEndpointId, mClusterId, Attributes::SupportedAreas::Id); } void Instance::NotifySupportedMapsChanged() @@ -417,14 +417,14 @@ void Instance::NotifySupportedMapsChanged() MatterReportingAttributeChangeCallback(mEndpointId, mClusterId, Attributes::SupportedMaps::Id); } -void Instance::NotifySelectedLocationsChanged() +void Instance::NotifySelectedAreasChanged() { - MatterReportingAttributeChangeCallback(mEndpointId, mClusterId, Attributes::SelectedLocations::Id); + MatterReportingAttributeChangeCallback(mEndpointId, mClusterId, Attributes::SelectedAreas::Id); } -void Instance::NotifyCurrentLocationChanged() +void Instance::NotifyCurrentAreaChanged() { - MatterReportingAttributeChangeCallback(mEndpointId, mClusterId, Attributes::CurrentLocation::Id); + MatterReportingAttributeChangeCallback(mEndpointId, mClusterId, Attributes::CurrentArea::Id); } void Instance::NotifyEstimatedEndTimeChanged() @@ -440,43 +440,43 @@ void Instance::NotifyProgressChanged() // **************************************************************************** // Supported Locations manipulators -bool Instance::IsSupportedLocation(uint32_t aLocationId) +bool Instance::IsSupportedLocation(uint32_t aAreaId) { uint32_t ignoredIndex; - LocationStructureWrapper ignoredLocation; + AreaStructureWrapper ignoredLocation; - return mDelegate->GetSupportedLocationById(aLocationId, ignoredIndex, ignoredLocation); + return mDelegate->GetSupportedLocationById(aAreaId, ignoredIndex, ignoredLocation); } -bool Instance::IsValidSupportedLocation(const LocationStructureWrapper & aLocation) +bool Instance::IsValidSupportedLocation(const AreaStructureWrapper & aLocation) { // If the HomeLocationInfo field is null, the LandmarkTag field SHALL NOT be null. // If the LandmarkTag field is null, the HomeLocationInfo field SHALL NOT be null. - if (aLocation.locationInfo.locationInfo.IsNull() && aLocation.locationInfo.landmarkTag.IsNull()) + if (aLocation.areaDesc.locationInfo.IsNull() && aLocation.areaDesc.landmarkTag.IsNull()) { - ChipLogDetail(Zcl, "IsValidAsSupportedLocation %u - must have locationInfo and/or LandmarkTag", aLocation.locationID); + ChipLogDetail(Zcl, "IsValidAsSupportedLocation %u - must have locationInfo and/or LandmarkTag", aLocation.areaID); return false; } // If HomeLocationInfo is not null, and its LocationName field is an empty string, at least one of the following SHALL NOT // be null: HomeLocationInfo's FloorNumber field, HomeLocationInfo's AreaType field, the LandmarkTag field - if (!aLocation.locationInfo.locationInfo.IsNull()) + if (!aLocation.areaDesc.locationInfo.IsNull()) { - if (aLocation.locationInfo.locationInfo.Value().locationName.empty() && - aLocation.locationInfo.locationInfo.Value().floorNumber.IsNull() && - aLocation.locationInfo.locationInfo.Value().areaType.IsNull() && aLocation.locationInfo.landmarkTag.IsNull()) + if (aLocation.areaDesc.locationInfo.Value().locationName.empty() && + aLocation.areaDesc.locationInfo.Value().floorNumber.IsNull() && + aLocation.areaDesc.locationInfo.Value().areaType.IsNull() && aLocation.areaDesc.landmarkTag.IsNull()) { ChipLogDetail( Zcl, "IsValidAsSupportedLocation %u - LocationName is empty string, FloorNumber, AreaType, LandmarkTag are null", - aLocation.locationID); + aLocation.areaID); return false; } } // If the LandmarkTag field is null, the PositionTag field SHALL be null. - if (aLocation.locationInfo.landmarkTag.IsNull() && !aLocation.locationInfo.positionTag.IsNull()) + if (aLocation.areaDesc.landmarkTag.IsNull() && !aLocation.areaDesc.positionTag.IsNull()) { - ChipLogDetail(Zcl, "IsValidAsSupportedLocation %u - PositionTag with no LandmarkTag", aLocation.locationID); + ChipLogDetail(Zcl, "IsValidAsSupportedLocation %u - PositionTag with no LandmarkTag", aLocation.areaID); return false; } @@ -485,7 +485,7 @@ bool Instance::IsValidSupportedLocation(const LocationStructureWrapper & aLocati // If the SupportedMaps attribute is null, mapid SHALL be null. if (!aLocation.mapID.IsNull()) { - ChipLogDetail(Zcl, "IsValidSupportedLocation %u - map Id %u is not in empty supported map list", aLocation.locationID, + ChipLogDetail(Zcl, "IsValidSupportedLocation %u - map Id %u is not in empty supported map list", aLocation.areaID, aLocation.mapID.Value()); return false; } @@ -495,7 +495,7 @@ bool Instance::IsValidSupportedLocation(const LocationStructureWrapper & aLocati // If the SupportedMaps attribute is not null, mapID SHALL be the ID of an entry from the SupportedMaps attribute. if (!IsSupportedMap(aLocation.mapID.Value())) { - ChipLogError(Zcl, "IsValidSupportedLocation %u - map Id %u is not in supported map list", aLocation.locationID, + ChipLogError(Zcl, "IsValidSupportedLocation %u - map Id %u is not in supported map list", aLocation.areaID, aLocation.mapID.Value()); return false; } @@ -504,13 +504,13 @@ bool Instance::IsValidSupportedLocation(const LocationStructureWrapper & aLocati return true; } -bool Instance::IsUniqueSupportedLocation(const LocationStructureWrapper & aLocation, bool ignoreLocationId) +bool Instance::IsUniqueSupportedLocation(const AreaStructureWrapper & aLocation, bool ignoreAreaId) { - BitMask config; + BitMask config; - if (ignoreLocationId) + if (ignoreAreaId) { - config.Set(LocationStructureWrapper::IsEqualConfig::kIgnoreLocationId); + config.Set(AreaStructureWrapper::IsEqualConfig::kIgnoreAreaID); } // If the SupportedMaps attribute is not null, each entry in this list SHALL have a unique value for the combination of the @@ -518,11 +518,11 @@ bool Instance::IsUniqueSupportedLocation(const LocationStructureWrapper & aLocat // the LocationInfo field. if (mDelegate->GetNumberOfSupportedMaps() == 0) { - config.Set(LocationStructureWrapper::IsEqualConfig::kIgnoreMapId); + config.Set(AreaStructureWrapper::IsEqualConfig::kIgnoreMapId); } uint8_t locationIndex = 0; - LocationStructureWrapper entry; + AreaStructureWrapper entry; while (mDelegate->GetSupportedLocationByIndex(locationIndex++, entry)) { if (aLocation.IsEqual(entry, config)) @@ -571,34 +571,33 @@ bool Instance::ReportEstimatedEndTimeChange(const DataModel::Nullable return (aEstimatedEndTime.Value() < mEstimatedEndTime.Value()); } -bool Instance::AddSupportedLocation(uint32_t aLocationId, const DataModel::Nullable & aMapId, - const CharSpan & aLocationName, const DataModel::Nullable & aFloorNumber, +bool Instance::AddSupportedLocation(uint32_t aAreaId, const DataModel::Nullable & aMapId, const CharSpan & aLocationName, + const DataModel::Nullable & aFloorNumber, const DataModel::Nullable & aAreaType, const DataModel::Nullable & aLandmarkTag, const DataModel::Nullable & aPositionTag, const DataModel::Nullable & aSurfaceTag) { // Create location object for validation. - LocationStructureWrapper aNewLocation(aLocationId, aMapId, aLocationName, aFloorNumber, aAreaType, aLandmarkTag, aPositionTag, - aSurfaceTag); + AreaStructureWrapper aNewArea(aAreaId, aMapId, aLocationName, aFloorNumber, aAreaType, aLandmarkTag, aPositionTag, aSurfaceTag); // Does device mode allow this attribute to be updated? - if (!mDelegate->IsSupportedLocationsChangeAllowed()) + if (!mDelegate->IsSupportedAreasChangeAllowed()) { return false; } // Check there is space for the entry. - if (mDelegate->GetNumberOfSupportedLocations() >= kMaxNumSupportedLocations) + if (mDelegate->GetNumberOfSupportedAreas() >= kMaxNumSupportedAreas) { - ChipLogError(Zcl, "AddSupportedLocation %u - too many entries", aLocationId); + ChipLogError(Zcl, "AddSupportedLocation %u - too many entries", aAreaId); return false; } // Verify cluster requirements concerning valid fields and field relationships. - if (!IsValidSupportedLocation(aNewLocation)) + if (!IsValidSupportedLocation(aNewArea)) { - ChipLogError(Zcl, "AddSupportedLocation %u - not a valid location object", aNewLocation.locationID); + ChipLogError(Zcl, "AddSupportedLocation %u - not a valid location object", aNewArea.areaID); return false; } @@ -606,24 +605,24 @@ bool Instance::AddSupportedLocation(uint32_t aLocationId, const DataModel::Nulla // If the SupportedMaps attribute is not null, each entry in this list SHALL have a unique value for the combination of the // MapID and LocationInfo fields. If the SupportedMaps attribute is null, each entry in this list SHALL have a unique value for // the LocationInfo field. - if (!IsUniqueSupportedLocation(aNewLocation, false)) + if (!IsUniqueSupportedLocation(aNewArea, false)) { - ChipLogError(Zcl, "AddSupportedLocation %u - not a unique location object", aNewLocation.locationID); + ChipLogError(Zcl, "AddSupportedLocation %u - not a unique location object", aNewArea.areaID); return false; } - // Add the SupportedLocation to the SupportedLocations attribute. + // Add the SupportedLocation to the SupportedAreas attribute. uint32_t ignoredIndex; - if (!mDelegate->AddSupportedLocation(aNewLocation, ignoredIndex)) + if (!mDelegate->AddSupportedLocation(aNewArea, ignoredIndex)) { return false; } - NotifySupportedLocationsChanged(); + NotifySupportedAreasChanged(); return true; } -bool Instance::ModifySupportedLocation(uint32_t aLocationId, const DataModel::Nullable & aMapId, +bool Instance::ModifySupportedLocation(uint32_t aAreaId, const DataModel::Nullable & aMapId, const CharSpan & aLocationName, const DataModel::Nullable & aFloorNumber, const DataModel::Nullable & aAreaType, const DataModel::Nullable & aLandmarkTag, @@ -634,10 +633,10 @@ bool Instance::ModifySupportedLocation(uint32_t aLocationId, const DataModel::Nu uint32_t listIndex; // get existing supported location to modify - LocationStructureWrapper supportedLocation; - if (!mDelegate->GetSupportedLocationById(aLocationId, listIndex, supportedLocation)) + AreaStructureWrapper supportedLocation; + if (!mDelegate->GetSupportedLocationById(aAreaId, listIndex, supportedLocation)) { - ChipLogError(Zcl, "ModifySupportedLocation %u - not a supported locationID", aLocationId); + ChipLogError(Zcl, "ModifySupportedLocation %u - not a supported areaID", aAreaId); return false; } @@ -647,7 +646,7 @@ bool Instance::ModifySupportedLocation(uint32_t aLocationId, const DataModel::Nu (!aMapId.IsNull() && !supportedLocation.mapID.IsNull() && (aMapId.Value() != supportedLocation.mapID.Value()))) { // does device mode allow this attribute to be updated? - if (!mDelegate->IsSupportedLocationsChangeAllowed()) + if (!mDelegate->IsSupportedAreasChangeAllowed()) { return false; } @@ -655,26 +654,26 @@ bool Instance::ModifySupportedLocation(uint32_t aLocationId, const DataModel::Nu } // create new location object for validation - LocationStructureWrapper aNewLocation(aLocationId, aMapId, aLocationName, aFloorNumber, aAreaType, aLandmarkTag, - aPositionTag, aSurfaceTag); + AreaStructureWrapper aNewArea(aAreaId, aMapId, aLocationName, aFloorNumber, aAreaType, aLandmarkTag, aPositionTag, + aSurfaceTag); // verify cluster requirements concerning valid fields and field relationships - if (!IsValidSupportedLocation(aNewLocation)) + if (!IsValidSupportedLocation(aNewArea)) { - ChipLogError(Zcl, "ModifySupportedLocation %u - not a valid location object", aNewLocation.locationID); + ChipLogError(Zcl, "ModifySupportedLocation %u - not a valid location object", aNewArea.areaID); return false; } // Updated location description must not match another existing location description. - // We ignore comparing the location ID as one of the locations will match this one. - if (!IsUniqueSupportedLocation(aNewLocation, true)) + // We ignore comparing the area ID as one of the locations will match this one. + if (!IsUniqueSupportedLocation(aNewArea, true)) { - ChipLogError(Zcl, "ModifySupportedLocation %u - not a unique location object", aNewLocation.locationID); + ChipLogError(Zcl, "ModifySupportedLocation %u - not a unique location object", aNewArea.areaID); return false; } // Replace the supported location with the modified location. - if (!mDelegate->ModifySupportedLocation(listIndex, aNewLocation)) + if (!mDelegate->ModifySupportedLocation(listIndex, aNewArea)) { return false; } @@ -682,25 +681,25 @@ bool Instance::ModifySupportedLocation(uint32_t aLocationId, const DataModel::Nu if (mapIDChanged) { - mDelegate->HandleSupportedLocationsUpdated(); + mDelegate->HandleSupportedAreasUpdated(); } - NotifySupportedLocationsChanged(); + NotifySupportedAreasChanged(); return true; } -bool Instance::ClearSupportedLocations() +bool Instance::ClearSupportedAreas() { // does device mode allow this attribute to be updated? - if (!mDelegate->IsSupportedLocationsChangeAllowed()) + if (!mDelegate->IsSupportedAreasChangeAllowed()) { return false; } - if (mDelegate->ClearSupportedLocations()) + if (mDelegate->ClearSupportedAreas()) { - mDelegate->HandleSupportedLocationsUpdated(); - NotifySupportedLocationsChanged(); + mDelegate->HandleSupportedAreasUpdated(); + NotifySupportedAreasChanged(); return true; } @@ -834,7 +833,7 @@ bool Instance::ClearSupportedMaps() if (mDelegate->ClearSupportedMaps()) { - ClearSupportedLocations(); + ClearSupportedAreas(); NotifySupportedMapsChanged(); return true; } @@ -848,13 +847,13 @@ bool Instance::ClearSupportedMaps() bool Instance::AddSelectedLocation(uint32_t & aSelectedLocation) { // check max# of list entries - if (mDelegate->GetNumberOfSelectedLocations() >= kMaxNumSelectedLocations) + if (mDelegate->GetNumberOfSelectedAreas() >= kMaxNumSelectedAreas) { ChipLogError(Zcl, "AddSelectedLocation %u - maximum number of entries", aSelectedLocation); return false; } - // each item in this list SHALL match the LocationID field of an entry on the SupportedLocations attribute's list + // each item in this list SHALL match the AreaID field of an entry on the SupportedAreas attribute's list if (!IsSupportedLocation(aSelectedLocation)) { ChipLogError(Zcl, "AddSelectedLocation %u - not a supported location", aSelectedLocation); @@ -872,7 +871,7 @@ bool Instance::AddSelectedLocation(uint32_t & aSelectedLocation) char locationStatusBuffer[kMaxSizeStatusText]; MutableCharSpan locationStatusText(locationStatusBuffer); - if (!mDelegate->IsSetSelectedLocationsAllowed(locationStatusText)) + if (!mDelegate->IsSetSelectedAreasAllowed(locationStatusText)) { ChipLogError(Zcl, "AddSelectedLocation %u - %.*s", aSelectedLocation, static_cast(locationStatusText.size()), locationStatusText.data()); @@ -883,11 +882,11 @@ bool Instance::AddSelectedLocation(uint32_t & aSelectedLocation) return mDelegate->AddSelectedLocation(aSelectedLocation, ignoredIndex); } -bool Instance::ClearSelectedLocations() +bool Instance::ClearSelectedAreas() { - if (mDelegate->ClearSelectedLocations()) + if (mDelegate->ClearSelectedAreas()) { - NotifySelectedLocationsChanged(); + NotifySelectedAreasChanged(); return true; } @@ -897,31 +896,31 @@ bool Instance::ClearSelectedLocations() //************************************************************************* // Current Location manipulators -DataModel::Nullable Instance::GetCurrentLocation() +DataModel::Nullable Instance::GetCurrentArea() { - return mCurrentLocation; + return mCurrentArea; } -bool Instance::SetCurrentLocation(const DataModel::Nullable & aCurrentLocation) +bool Instance::SetCurrentArea(const DataModel::Nullable & aCurrentArea) { - // If not null, the value of this attribute SHALL match the LocationID field of an entry on the SupportedLocations attribute's + // If not null, the value of this attribute SHALL match the AreaID field of an entry on the SupportedAreas attribute's // list. - if ((!aCurrentLocation.IsNull()) && (!IsSupportedLocation(aCurrentLocation.Value()))) + if ((!aCurrentArea.IsNull()) && (!IsSupportedLocation(aCurrentArea.Value()))) { - ChipLogError(Zcl, "SetCurrentLocation %u - location is not supported", aCurrentLocation.Value()); + ChipLogError(Zcl, "SetCurrentArea %u - location is not supported", aCurrentArea.Value()); return false; } - bool notifyChange = mCurrentLocation != aCurrentLocation; + bool notifyChange = mCurrentArea != aCurrentArea; - mCurrentLocation = aCurrentLocation; + mCurrentArea = aCurrentArea; if (notifyChange) { - NotifyCurrentLocationChanged(); + NotifyCurrentAreaChanged(); } - // EstimatedEndTime SHALL be null if the CurrentLocation attribute is null. - if (mCurrentLocation.IsNull()) + // EstimatedEndTime SHALL be null if the CurrentArea attribute is null. + if (mCurrentArea.IsNull()) { SetEstimatedEndTime(DataModel::NullNullable); } @@ -939,8 +938,8 @@ DataModel::Nullable Instance::GetEstimatedEndTime() bool Instance::SetEstimatedEndTime(const DataModel::Nullable & aEstimatedEndTime) { - // EstimatedEndTime SHALL be null if the CurrentLocation attribute is null. - if (mCurrentLocation.IsNull() && !aEstimatedEndTime.IsNull()) + // EstimatedEndTime SHALL be null if the CurrentArea attribute is null. + if (mCurrentArea.IsNull() && !aEstimatedEndTime.IsNull()) { ChipLogError(Zcl, "SetEstimatedEndTime - must be null if Current Location is null"); return false; @@ -962,10 +961,10 @@ bool Instance::SetEstimatedEndTime(const DataModel::Nullable & aEstima //************************************************************************* // Progress list manipulators -bool Instance::AddPendingProgressElement(uint32_t aLocationId) +bool Instance::AddPendingProgressElement(uint32_t aAreaId) { // create progress element - Structs::ProgressStruct::Type inactiveProgress = { aLocationId, OperationalStatusEnum::kPending }; + Structs::ProgressStruct::Type inactiveProgress = { aAreaId, OperationalStatusEnum::kPending }; // check max# of list entries if (mDelegate->GetNumberOfProgressElements() >= kMaxNumProgressElements) @@ -974,17 +973,17 @@ bool Instance::AddPendingProgressElement(uint32_t aLocationId) return false; } - // For each entry in this list, the LocationID field SHALL match an entry on the SupportedLocations attribute's list. - if (!IsSupportedLocation(aLocationId)) + // For each entry in this list, the AreaID field SHALL match an entry on the SupportedAreas attribute's list. + if (!IsSupportedLocation(aAreaId)) { - ChipLogError(Zcl, "AddPendingProgressElement - not a supported location %u", aLocationId); + ChipLogError(Zcl, "AddPendingProgressElement - not a supported location %u", aAreaId); return false; } - // Each entry in this list SHALL have a unique value for the LocationID field. - if (mDelegate->IsProgressElement(aLocationId)) + // Each entry in this list SHALL have a unique value for the AreaID field. + if (mDelegate->IsProgressElement(aAreaId)) { - ChipLogError(Zcl, "AddPendingProgressElement - progress element already exists for location %u", aLocationId); + ChipLogError(Zcl, "AddPendingProgressElement - progress element already exists for location %u", aAreaId); return false; } @@ -999,14 +998,14 @@ bool Instance::AddPendingProgressElement(uint32_t aLocationId) return true; } -bool Instance::SetProgressStatus(uint32_t aLocationId, OperationalStatusEnum opStatus) +bool Instance::SetProgressStatus(uint32_t aAreaId, OperationalStatusEnum opStatus) { uint32_t listIndex; Structs::ProgressStruct::Type progressElement; - if (!mDelegate->GetProgressElementById(aLocationId, listIndex, progressElement)) + if (!mDelegate->GetProgressElementById(aAreaId, listIndex, progressElement)) { - ChipLogError(Zcl, "SetProgressStatus - progress element does not exist for location %u", aLocationId); + ChipLogError(Zcl, "SetProgressStatus - progress element does not exist for location %u", aAreaId); return false; } @@ -1035,14 +1034,14 @@ bool Instance::SetProgressStatus(uint32_t aLocationId, OperationalStatusEnum opS return true; } -bool Instance::SetProgressTotalOperationalTime(uint32_t aLocationId, const DataModel::Nullable & aTotalOperationalTime) +bool Instance::SetProgressTotalOperationalTime(uint32_t aAreaId, const DataModel::Nullable & aTotalOperationalTime) { uint32_t listIndex; Structs::ProgressStruct::Type progressElement; - if (!mDelegate->GetProgressElementById(aLocationId, listIndex, progressElement)) + if (!mDelegate->GetProgressElementById(aAreaId, listIndex, progressElement)) { - ChipLogError(Zcl, "SetProgressTotalOperationalTime - progress element does not exist for location %u", aLocationId); + ChipLogError(Zcl, "SetProgressTotalOperationalTime - progress element does not exist for location %u", aAreaId); return false; } @@ -1060,7 +1059,7 @@ bool Instance::SetProgressTotalOperationalTime(uint32_t aLocationId, const DataM ChipLogError(Zcl, "SetProgressTotalOperationalTime - location %u opStatus value %u - can be non-null only if opStatus is " "Completed or Skipped", - aLocationId, to_underlying(progressElement.status)); + aAreaId, to_underlying(progressElement.status)); return false; } @@ -1077,14 +1076,14 @@ bool Instance::SetProgressTotalOperationalTime(uint32_t aLocationId, const DataM return true; } -bool Instance::SetProgressEstimatedTime(uint32_t aLocationId, const DataModel::Nullable & aEstimatedTime) +bool Instance::SetProgressEstimatedTime(uint32_t aAreaId, const DataModel::Nullable & aEstimatedTime) { uint32_t listIndex; Structs::ProgressStruct::Type progressElement; - if (!mDelegate->GetProgressElementById(aLocationId, listIndex, progressElement)) + if (!mDelegate->GetProgressElementById(aAreaId, listIndex, progressElement)) { - ChipLogError(Zcl, "SetProgressEstimatedTime - progress element does not exist for location %u", aLocationId); + ChipLogError(Zcl, "SetProgressEstimatedTime - progress element does not exist for location %u", aAreaId); return false; } diff --git a/src/app/clusters/service-area-server/service-area-server.h b/src/app/clusters/service-area-server/service-area-server.h index d781987c8d26dd..90cf4275cf3871 100644 --- a/src/app/clusters/service-area-server/service-area-server.h +++ b/src/app/clusters/service-area-server/service-area-server.h @@ -79,7 +79,7 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface ClusterId mClusterId; // Attribute Data Store - DataModel::Nullable mCurrentLocation; + DataModel::Nullable mCurrentArea; DataModel::Nullable mEstimatedEndTime; BitMask mFeature; @@ -101,11 +101,11 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface //************************************************************************* // attribute readers - CHIP_ERROR ReadSupportedLocations(chip::app::AttributeValueEncoder & aEncoder); + CHIP_ERROR ReadSupportedAreas(chip::app::AttributeValueEncoder & aEncoder); CHIP_ERROR ReadSupportedMaps(chip::app::AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadSelectedLocations(chip::app::AttributeValueEncoder & aEncoder); + CHIP_ERROR ReadSelectedAreas(chip::app::AttributeValueEncoder & aEncoder); CHIP_ERROR ReadProgress(chip::app::AttributeValueEncoder & aEncoder); @@ -117,21 +117,21 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface * If the input value is invalid, returns the Interaction Model status code of INVALID_COMMAND. * @param[in] req the command parameters */ - void HandleSelectLocationsCmd(HandlerContext & ctx, const Commands::SelectLocations::DecodableType & req); + void HandleSelectAreasCmd(HandlerContext & ctx, const Commands::SelectAreas::DecodableType & req); /** * @param[in, out] ctx Returns the Interaction Model status code which was user determined in the business logic. * If the input value is invalid, returns the Interaction Model status code of INVALID_COMMAND. */ - void HandleSkipCurrentLocationCmd(HandlerContext & ctx); + void HandleSkipCurrentAreaCmd(HandlerContext & ctx); //************************************************************************* // attribute notifications - void NotifySupportedLocationsChanged(); + void NotifySupportedAreasChanged(); void NotifySupportedMapsChanged(); - void NotifySelectedLocationsChanged(); - void NotifyCurrentLocationChanged(); + void NotifySelectedAreasChanged(); + void NotifyCurrentAreaChanged(); void NotifyEstimatedEndTimeChanged(); void NotifyProgressChanged(); @@ -139,25 +139,25 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface // Supported Locations manipulators /** - * @return true if a location with the aLocationId ID exists in the supported locations attribute. False otherwise. + * @return true if a location with the aAreaId ID exists in the supported locations attribute. False otherwise. */ - bool IsSupportedLocation(uint32_t aLocationId); + bool IsSupportedLocation(uint32_t aAreaId); /** * @brief Check if the given location adheres to the restrictions required by the supported locations attribute. * @return true if the aLocation meets all checks. */ - bool IsValidSupportedLocation(const LocationStructureWrapper & aLocation); + bool IsValidSupportedLocation(const AreaStructureWrapper & aLocation); /** * @brief check if aLocation is unique with regard to supported locations. * @param[in] aLocation the location to check. - * @param[out] ignoreLocationId if true, we do not check if the location ID is unique. + * @param[out] ignoreAreaId if true, we do not check if the area ID is unique. * @return true if there isn't a location in supported locations that matches aLocation. * * @note This method may ignore checking the MapId uniqueness. This depends on whether the SupportedMaps attribute is null. */ - bool IsUniqueSupportedLocation(const LocationStructureWrapper & aLocation, bool ignoreLocationId); + bool IsUniqueSupportedLocation(const AreaStructureWrapper & aLocation, bool ignoreAreaId); /** * @brief Check if changing the estimated end time attribute to aEstimatedEndTime requires the change to be reported. @@ -169,7 +169,7 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface public: /** * @brief Add new location to the supported locations list. - * @param[in] aLocationId unique identifier of this location. + * @param[in] aAreaId unique identifier of this location. * @param[in] aMapId identifier of supported map. * @param[in] aLocationName human readable name for this location (empty string if not used). * @param[in] aFloorNumber represents floor level - negative values for below ground. @@ -182,7 +182,7 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface * * @note if aLocationName is larger than kLocationNameMaxSize, it will be truncated. */ - bool AddSupportedLocation(uint32_t aLocationId, const DataModel::Nullable & aMapId, const CharSpan & aLocationName, + bool AddSupportedLocation(uint32_t aAreaId, const DataModel::Nullable & aMapId, const CharSpan & aLocationName, const DataModel::Nullable & aFloorNumber, const DataModel::Nullable & aAreaType, const DataModel::Nullable & aLandmarkTag, @@ -191,7 +191,7 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface /** * @brief Modify/replace an existing location in the supported locations list. - * @param[in] aLocationId unique identifier of this location. + * @param[in] aAreaId unique identifier of this location. * @param[in] aMapId identifier of supported map (will not be modified). * @param[in] aLocationName human readable name for this location (empty string if not used). * @param[in] aFloorNumber represents floor level - negative values for below ground. @@ -204,9 +204,9 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface * location was modified. * * @note if aLocationName is larger than kLocationNameMaxSize, it will be truncated. - * @note if mapID is changed, the delegate's HandleSupportedLocationsUpdated method is called. + * @note if mapID is changed, the delegate's HandleSupportedAreasUpdated method is called. */ - bool ModifySupportedLocation(uint32_t aLocationId, const DataModel::Nullable & aMapId, const CharSpan & aLocationName, + bool ModifySupportedLocation(uint32_t aAreaId, const DataModel::Nullable & aMapId, const CharSpan & aLocationName, const DataModel::Nullable & aFloorNumber, const DataModel::Nullable & aAreaType, const DataModel::Nullable & aLandmarkTag, @@ -214,11 +214,11 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface const DataModel::Nullable & aSurfaceTag); /** - * @return true if the SupportedLocations attribute was not already null. + * @return true if the SupportedAreas attribute was not already null. * - * @note if SupportedLocations is cleared, the delegate's HandleSupportedLocationsUpdated method is called. + * @note if SupportedAreas is cleared, the delegate's HandleSupportedAreasUpdated method is called. */ - bool ClearSupportedLocations(); + bool ClearSupportedAreas(); //************************************************************************* // Supported Maps manipulators @@ -249,7 +249,7 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface /** * @return true if the SupportedMaps attribute was not already null. * - * @note if SupportedMaps is cleared, the delegate's HandleSupportedLocationsUpdated method is called. + * @note if SupportedMaps is cleared, the delegate's HandleSupportedAreasUpdated method is called. */ bool ClearSupportedMaps(); @@ -258,42 +258,42 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface /** * @brief Add a selected location. - * @param[in] aSelectedLocation The locationID to add. + * @param[in] aSelectedLocation The areaID to add. * @bool true if successfully added. */ bool AddSelectedLocation(uint32_t & aSelectedLocation); /** - * @return true if the SelectedLocations attribute was not already null. + * @return true if the SelectedAreas attribute was not already null. */ - bool ClearSelectedLocations(); + bool ClearSelectedAreas(); //************************************************************************* // Current Location manipulators - DataModel::Nullable GetCurrentLocation(); + DataModel::Nullable GetCurrentArea(); /** - * @param[in] aCurrentLocation The location ID that the CurrentLocation attribute should be set to. Must be a supported location + * @param[in] aCurrentArea The area ID that the CurrentArea attribute should be set to. Must be a supported location * or NULL. * @return true if the current location is set, false otherwise. * * @note if current location is set to null, estimated end time will be set to null. */ - bool SetCurrentLocation(const DataModel::Nullable & aCurrentLocation); + bool SetCurrentArea(const DataModel::Nullable & aCurrentArea); //************************************************************************* // Estimated End Time manipulators /** - * @return The estimated epoch time in seconds when operation at the location indicated by the CurrentLocation attribute will be + * @return The estimated epoch time in seconds when operation at the location indicated by the CurrentArea attribute will be * completed. */ DataModel::Nullable GetEstimatedEndTime(); /** * @param[in] aEstimatedEndTime The estimated epoch time in seconds when operation at the location indicated by the - * CurrentLocation attribute will be completed. + * CurrentArea attribute will be completed. * @return true if attribute is set, false otherwise. */ bool SetEstimatedEndTime(const DataModel::Nullable & aEstimatedEndTime); @@ -303,36 +303,36 @@ class Instance : public AttributeAccessInterface, public CommandHandlerInterface /** * @brief Add a progress element in a pending status to the progress list. - * @param[in] aLocationId location id of the progress element. + * @param[in] aAreaId location id of the progress element. * @return true if the new progress element passed validation checks and was successfully added to the list, false otherwise. */ - bool AddPendingProgressElement(uint32_t aLocationId); + bool AddPendingProgressElement(uint32_t aAreaId); /** - * @brief Set the status of progress element identified by locationID. - * @param[in] aLocationId The locationID of the progress element to update. + * @brief Set the status of progress element identified by areaID. + * @param[in] aAreaId The areaID of the progress element to update. * @param[in] status The location cluster operation status for this location. * @return true if progress element is found and status is set, false otherwise. * * @note TotalOperationalTime is set to null if resulting opStatus is not equal to Completed or Skipped. */ - bool SetProgressStatus(uint32_t aLocationId, OperationalStatusEnum opStatus); + bool SetProgressStatus(uint32_t aAreaId, OperationalStatusEnum opStatus); /** - * @brief Set the total operational time for the progress element identified by locationID. - * @param[in] aLocationId The locationID of the progress element to update. + * @brief Set the total operational time for the progress element identified by areaID. + * @param[in] aAreaId The areaID of the progress element to update. * @param[in] aTotalOperationalTime The total operational time for this location. * @return true if progress element is found and operational time is set, false otherwise. */ - bool SetProgressTotalOperationalTime(uint32_t aLocationId, const DataModel::Nullable & aTotalOperationalTime); + bool SetProgressTotalOperationalTime(uint32_t aAreaId, const DataModel::Nullable & aTotalOperationalTime); /** - * @brief Set the estimated time for the progress element identified by locationID. - * @param[in] aLocationId The locationID of the progress element to update. + * @brief Set the estimated time for the progress element identified by areaID. + * @param[in] aAreaId The areaID of the progress element to update. * @param[in] aEstimatedTime The estimated time for this location. * @return true if progress element is found and estimated time is set, false otherwise. */ - bool SetProgressEstimatedTime(uint32_t aLocationId, const DataModel::Nullable & aEstimatedTime); + bool SetProgressEstimatedTime(uint32_t aAreaId, const DataModel::Nullable & aEstimatedTime); /** * @return true if the progress list was not already null, false otherwise. diff --git a/src/app/zap-templates/zcl/data-model/chip/service-area-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/service-area-cluster.xml index 3332172500e451..f78e8966a11b94 100644 --- a/src/app/zap-templates/zcl/data-model/chip/service-area-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/service-area-cluster.xml @@ -18,7 +18,7 @@ limitations under the License. Data types - + @@ -32,11 +32,11 @@ limitations under the License. - + - - - + + + @@ -49,25 +49,25 @@ limitations under the License. - + - + - - + + - + - + @@ -88,41 +88,41 @@ limitations under the License. - SupportedLocations + SupportedAreas SupportedMaps - SelectedLocations - CurrentLocation + SelectedAreas + CurrentArea EstimatedEndTime - Progress + Progress - + - Command used to select a set of device locations, where the device is to operate + Command used to select a set of device areas, where the device is to operate. - + - + - This command is sent by the device on receipt of the SelectLocations command. + This command is sent by the device on receipt of the SelectAreas command. - + - + - This command is used to skip the current location where the device operates. + This command is used to skip an area where the device operates. - + - This command is sent by the device on receipt of the SelectLocations command. + This command is sent by the device on receipt of the SkipArea command. - - + + diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index d826188bbfd700..3a19eba34b745a 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -681,7 +681,7 @@ "ThreadNetworks", "ThreadNetworkTableSize" ], - "Service Area": ["CurrentLocation", "EstimatedEndTime", "FeatureMap"] + "Service Area": ["CurrentArea", "EstimatedEndTime", "FeatureMap"] }, "defaultReportingPolicy": "mandatory", "ZCLDataTypes": ["ARRAY", "BITMAP", "ENUM", "NUMBER", "STRING", "STRUCT"], diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index a5d48c88b540a0..4714e240bbf3a3 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -679,7 +679,7 @@ "ThreadNetworks", "ThreadNetworkTableSize" ], - "Service Area": ["CurrentLocation", "EstimatedEndTime", "FeatureMap"] + "Service Area": ["CurrentArea", "EstimatedEndTime", "FeatureMap"] }, "defaultReportingPolicy": "mandatory", "ZCLDataTypes": ["ARRAY", "BITMAP", "ENUM", "NUMBER", "STRING", "STRUCT"], diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 62cb544805beff..c32f6412acdee0 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -6443,17 +6443,17 @@ provisional cluster ServiceArea = 336 { kCompleted = 3; } - enum SelectLocationsStatus : enum8 { + enum SelectAreasStatus : enum8 { kSuccess = 0; - kUnsupportedLocation = 1; - kDuplicatedLocations = 2; + kUnsupportedArea = 1; + kDuplicatedAreas = 2; kInvalidInMode = 3; kInvalidSet = 4; } - enum SkipCurrentLocationStatus : enum8 { + enum SkipAreaStatus : enum8 { kSuccess = 0; - kInvalidLocationList = 1; + kInvalidAreaList = 1; kInvalidInMode = 2; } @@ -6462,17 +6462,17 @@ provisional cluster ServiceArea = 336 { kSelectWhileRunning = 0x2; } - struct LocationInfoStruct { + struct AreaInfoStruct { nullable LocationDescriptorStruct locationInfo = 0; nullable LandmarkTag landmarkTag = 1; nullable PositionTag positionTag = 2; nullable FloorSurfaceTag surfaceTag = 3; } - struct LocationStruct { - int32u locationID = 0; + struct AreaStruct { + int32u areaID = 0; nullable int8u mapID = 1; - LocationInfoStruct locationInfo = 2; + AreaInfoStruct areaDesc = 2; } struct MapStruct { @@ -6481,16 +6481,16 @@ provisional cluster ServiceArea = 336 { } struct ProgressStruct { - int32u locationID = 0; + int32u areaID = 0; OperationalStatusEnum status = 1; optional nullable elapsed_s totalOperationalTime = 2; optional nullable elapsed_s estimatedTime = 3; } - readonly attribute LocationStruct supportedLocations[] = 0; + readonly attribute AreaStruct supportedAreas[] = 0; readonly attribute nullable MapStruct supportedMaps[] = 1; - readonly attribute nullable int32u selectedLocations[] = 2; - readonly attribute optional nullable int32u currentLocation = 3; + readonly attribute nullable int32u selectedAreas[] = 2; + readonly attribute optional nullable int32u currentArea = 3; readonly attribute optional nullable epoch_s estimatedEndTime = 4; readonly attribute optional nullable ProgressStruct progress[] = 5; readonly attribute command_id generatedCommandList[] = 65528; @@ -6500,24 +6500,24 @@ provisional cluster ServiceArea = 336 { readonly attribute bitmap32 featureMap = 65532; readonly attribute int16u clusterRevision = 65533; - request struct SelectLocationsRequest { - nullable int32u newLocations[] = 0; + request struct SelectAreasRequest { + nullable int32u newAreas[] = 0; } - response struct SelectLocationsResponse = 1 { - SelectLocationsStatus status = 0; + response struct SelectAreasResponse = 1 { + SelectAreasStatus status = 0; optional char_string<256> statusText = 1; } - response struct SkipCurrentLocationResponse = 3 { - SkipCurrentLocationStatus status = 0; + response struct SkipAreaResponse = 3 { + SkipAreaStatus status = 0; optional char_string<256> statusText = 1; } - /** Command used to select a set of device locations, where the device is to operate */ - command SelectLocations(SelectLocationsRequest): SelectLocationsResponse = 0; - /** This command is used to skip the current location where the device operates. */ - command SkipCurrentLocation(): SkipCurrentLocationResponse = 2; + /** Command used to select a set of device areas, where the device is to operate. */ + command SelectAreas(SelectAreasRequest): SelectAreasResponse = 0; + /** This command is used to skip an area where the device operates. */ + command SkipArea(): SkipAreaResponse = 2; } /** An interface for configuring and controlling pumps. */ diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index e8ba5badd39616..2ae10832fd10da 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -39050,10 +39050,10 @@ public void onSuccess(byte[] tlv) { public static class ServiceAreaCluster extends BaseChipCluster { public static final long CLUSTER_ID = 336L; - private static final long SUPPORTED_LOCATIONS_ATTRIBUTE_ID = 0L; + private static final long SUPPORTED_AREAS_ATTRIBUTE_ID = 0L; private static final long SUPPORTED_MAPS_ATTRIBUTE_ID = 1L; - private static final long SELECTED_LOCATIONS_ATTRIBUTE_ID = 2L; - private static final long CURRENT_LOCATION_ATTRIBUTE_ID = 3L; + private static final long SELECTED_AREAS_ATTRIBUTE_ID = 2L; + private static final long CURRENT_AREA_ATTRIBUTE_ID = 3L; private static final long ESTIMATED_END_TIME_ATTRIBUTE_ID = 4L; private static final long PROGRESS_ATTRIBUTE_ID = 5L; private static final long GENERATED_COMMAND_LIST_ATTRIBUTE_ID = 65528L; @@ -39073,17 +39073,17 @@ public long initWithDevice(long devicePtr, int endpointId) { return 0L; } - public void selectLocations(SelectLocationsResponseCallback callback, @Nullable ArrayList newLocations) { - selectLocations(callback, newLocations, 0); + public void selectAreas(SelectAreasResponseCallback callback, @Nullable ArrayList newAreas) { + selectAreas(callback, newAreas, 0); } - public void selectLocations(SelectLocationsResponseCallback callback, @Nullable ArrayList newLocations, int timedInvokeTimeoutMs) { + public void selectAreas(SelectAreasResponseCallback callback, @Nullable ArrayList newAreas, int timedInvokeTimeoutMs) { final long commandId = 0L; ArrayList elements = new ArrayList<>(); - final long newLocationsFieldID = 0L; - BaseTLVType newLocationstlvValue = newLocations != null ? ArrayType.generateArrayType(newLocations, (elementnewLocations) -> new UIntType(elementnewLocations)) : new NullType(); - elements.add(new StructElement(newLocationsFieldID, newLocationstlvValue)); + final long newAreasFieldID = 0L; + BaseTLVType newAreastlvValue = newAreas != null ? ArrayType.generateArrayType(newAreas, (elementnewAreas) -> new UIntType(elementnewAreas)) : new NullType(); + elements.add(new StructElement(newAreasFieldID, newAreastlvValue)); StructType commandArgs = new StructType(elements); invoke(new InvokeCallbackImpl(callback) { @@ -39110,11 +39110,11 @@ public void onResponse(StructType invokeStructValue) { }}, commandId, commandArgs, timedInvokeTimeoutMs); } - public void skipCurrentLocation(SkipCurrentLocationResponseCallback callback) { - skipCurrentLocation(callback, 0); + public void skipArea(SkipAreaResponseCallback callback) { + skipArea(callback, 0); } - public void skipCurrentLocation(SkipCurrentLocationResponseCallback callback, int timedInvokeTimeoutMs) { + public void skipArea(SkipAreaResponseCallback callback, int timedInvokeTimeoutMs) { final long commandId = 2L; ArrayList elements = new ArrayList<>(); @@ -39143,27 +39143,27 @@ public void onResponse(StructType invokeStructValue) { }}, commandId, commandArgs, timedInvokeTimeoutMs); } - public interface SelectLocationsResponseCallback extends BaseClusterCallback { + public interface SelectAreasResponseCallback extends BaseClusterCallback { void onSuccess(Integer status, Optional statusText); } - public interface SkipCurrentLocationResponseCallback extends BaseClusterCallback { + public interface SkipAreaResponseCallback extends BaseClusterCallback { void onSuccess(Integer status, Optional statusText); } - public interface SupportedLocationsAttributeCallback extends BaseAttributeCallback { - void onSuccess(List value); + public interface SupportedAreasAttributeCallback extends BaseAttributeCallback { + void onSuccess(List value); } public interface SupportedMapsAttributeCallback extends BaseAttributeCallback { void onSuccess(@Nullable List value); } - public interface SelectedLocationsAttributeCallback extends BaseAttributeCallback { + public interface SelectedAreasAttributeCallback extends BaseAttributeCallback { void onSuccess(@Nullable List value); } - public interface CurrentLocationAttributeCallback extends BaseAttributeCallback { + public interface CurrentAreaAttributeCallback extends BaseAttributeCallback { void onSuccess(@Nullable Long value); } @@ -39191,30 +39191,30 @@ public interface AttributeListAttributeCallback extends BaseAttributeCallback { void onSuccess(List value); } - public void readSupportedLocationsAttribute( - SupportedLocationsAttributeCallback callback) { - ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SUPPORTED_LOCATIONS_ATTRIBUTE_ID); + public void readSupportedAreasAttribute( + SupportedAreasAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SUPPORTED_AREAS_ATTRIBUTE_ID); readAttribute(new ReportCallbackImpl(callback, path) { @Override public void onSuccess(byte[] tlv) { - List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } - }, SUPPORTED_LOCATIONS_ATTRIBUTE_ID, true); + }, SUPPORTED_AREAS_ATTRIBUTE_ID, true); } - public void subscribeSupportedLocationsAttribute( - SupportedLocationsAttributeCallback callback, int minInterval, int maxInterval) { - ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SUPPORTED_LOCATIONS_ATTRIBUTE_ID); + public void subscribeSupportedAreasAttribute( + SupportedAreasAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SUPPORTED_AREAS_ATTRIBUTE_ID); subscribeAttribute(new ReportCallbackImpl(callback, path) { @Override public void onSuccess(byte[] tlv) { - List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } - }, SUPPORTED_LOCATIONS_ATTRIBUTE_ID, minInterval, maxInterval); + }, SUPPORTED_AREAS_ATTRIBUTE_ID, minInterval, maxInterval); } public void readSupportedMapsAttribute( @@ -39243,9 +39243,9 @@ public void onSuccess(byte[] tlv) { }, SUPPORTED_MAPS_ATTRIBUTE_ID, minInterval, maxInterval); } - public void readSelectedLocationsAttribute( - SelectedLocationsAttributeCallback callback) { - ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SELECTED_LOCATIONS_ATTRIBUTE_ID); + public void readSelectedAreasAttribute( + SelectedAreasAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SELECTED_AREAS_ATTRIBUTE_ID); readAttribute(new ReportCallbackImpl(callback, path) { @Override @@ -39253,12 +39253,12 @@ public void onSuccess(byte[] tlv) { @Nullable List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } - }, SELECTED_LOCATIONS_ATTRIBUTE_ID, true); + }, SELECTED_AREAS_ATTRIBUTE_ID, true); } - public void subscribeSelectedLocationsAttribute( - SelectedLocationsAttributeCallback callback, int minInterval, int maxInterval) { - ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SELECTED_LOCATIONS_ATTRIBUTE_ID); + public void subscribeSelectedAreasAttribute( + SelectedAreasAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SELECTED_AREAS_ATTRIBUTE_ID); subscribeAttribute(new ReportCallbackImpl(callback, path) { @Override @@ -39266,12 +39266,12 @@ public void onSuccess(byte[] tlv) { @Nullable List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } - }, SELECTED_LOCATIONS_ATTRIBUTE_ID, minInterval, maxInterval); + }, SELECTED_AREAS_ATTRIBUTE_ID, minInterval, maxInterval); } - public void readCurrentLocationAttribute( - CurrentLocationAttributeCallback callback) { - ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, CURRENT_LOCATION_ATTRIBUTE_ID); + public void readCurrentAreaAttribute( + CurrentAreaAttributeCallback callback) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, CURRENT_AREA_ATTRIBUTE_ID); readAttribute(new ReportCallbackImpl(callback, path) { @Override @@ -39279,12 +39279,12 @@ public void onSuccess(byte[] tlv) { @Nullable Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } - }, CURRENT_LOCATION_ATTRIBUTE_ID, true); + }, CURRENT_AREA_ATTRIBUTE_ID, true); } - public void subscribeCurrentLocationAttribute( - CurrentLocationAttributeCallback callback, int minInterval, int maxInterval) { - ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, CURRENT_LOCATION_ATTRIBUTE_ID); + public void subscribeCurrentAreaAttribute( + CurrentAreaAttributeCallback callback, int minInterval, int maxInterval) { + ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, CURRENT_AREA_ATTRIBUTE_ID); subscribeAttribute(new ReportCallbackImpl(callback, path) { @Override @@ -39292,7 +39292,7 @@ public void onSuccess(byte[] tlv) { @Nullable Long value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } - }, CURRENT_LOCATION_ATTRIBUTE_ID, minInterval, maxInterval); + }, CURRENT_AREA_ATTRIBUTE_ID, minInterval, maxInterval); } public void readEstimatedEndTimeAttribute( diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java b/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java index 9e32eaab03ffac..330ee797fb6ecb 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java @@ -9171,7 +9171,7 @@ public String toString() { return output.toString(); } } -public static class ServiceAreaClusterLocationInfoStruct { +public static class ServiceAreaClusterAreaInfoStruct { public @Nullable ChipStructs.ServiceAreaClusterLocationDescriptorStruct locationInfo; public @Nullable Integer landmarkTag; public @Nullable Integer positionTag; @@ -9181,7 +9181,7 @@ public static class ServiceAreaClusterLocationInfoStruct { private static final long POSITION_TAG_ID = 2L; private static final long SURFACE_TAG_ID = 3L; - public ServiceAreaClusterLocationInfoStruct( + public ServiceAreaClusterAreaInfoStruct( @Nullable ChipStructs.ServiceAreaClusterLocationDescriptorStruct locationInfo, @Nullable Integer landmarkTag, @Nullable Integer positionTag, @@ -9203,7 +9203,7 @@ public StructType encodeTlv() { return new StructType(values); } - public static ServiceAreaClusterLocationInfoStruct decodeTlv(BaseTLVType tlvValue) { + public static ServiceAreaClusterAreaInfoStruct decodeTlv(BaseTLVType tlvValue) { if (tlvValue == null || tlvValue.type() != TLVType.Struct) { return null; } @@ -9234,7 +9234,7 @@ public static ServiceAreaClusterLocationInfoStruct decodeTlv(BaseTLVType tlvValu } } } - return new ServiceAreaClusterLocationInfoStruct( + return new ServiceAreaClusterAreaInfoStruct( locationInfo, landmarkTag, positionTag, @@ -9245,7 +9245,7 @@ public static ServiceAreaClusterLocationInfoStruct decodeTlv(BaseTLVType tlvValu @Override public String toString() { StringBuilder output = new StringBuilder(); - output.append("ServiceAreaClusterLocationInfoStruct {\n"); + output.append("ServiceAreaClusterAreaInfoStruct {\n"); output.append("\tlocationInfo: "); output.append(locationInfo); output.append("\n"); @@ -9262,77 +9262,77 @@ public String toString() { return output.toString(); } } -public static class ServiceAreaClusterLocationStruct { - public Long locationID; +public static class ServiceAreaClusterAreaStruct { + public Long areaID; public @Nullable Integer mapID; - public ChipStructs.ServiceAreaClusterLocationInfoStruct locationInfo; - private static final long LOCATION_I_D_ID = 0L; + public ChipStructs.ServiceAreaClusterAreaInfoStruct areaDesc; + private static final long AREA_I_D_ID = 0L; private static final long MAP_I_D_ID = 1L; - private static final long LOCATION_INFO_ID = 2L; + private static final long AREA_DESC_ID = 2L; - public ServiceAreaClusterLocationStruct( - Long locationID, + public ServiceAreaClusterAreaStruct( + Long areaID, @Nullable Integer mapID, - ChipStructs.ServiceAreaClusterLocationInfoStruct locationInfo + ChipStructs.ServiceAreaClusterAreaInfoStruct areaDesc ) { - this.locationID = locationID; + this.areaID = areaID; this.mapID = mapID; - this.locationInfo = locationInfo; + this.areaDesc = areaDesc; } public StructType encodeTlv() { ArrayList values = new ArrayList<>(); - values.add(new StructElement(LOCATION_I_D_ID, new UIntType(locationID))); + values.add(new StructElement(AREA_I_D_ID, new UIntType(areaID))); values.add(new StructElement(MAP_I_D_ID, mapID != null ? new UIntType(mapID) : new NullType())); - values.add(new StructElement(LOCATION_INFO_ID, locationInfo.encodeTlv())); + values.add(new StructElement(AREA_DESC_ID, areaDesc.encodeTlv())); return new StructType(values); } - public static ServiceAreaClusterLocationStruct decodeTlv(BaseTLVType tlvValue) { + public static ServiceAreaClusterAreaStruct decodeTlv(BaseTLVType tlvValue) { if (tlvValue == null || tlvValue.type() != TLVType.Struct) { return null; } - Long locationID = null; + Long areaID = null; @Nullable Integer mapID = null; - ChipStructs.ServiceAreaClusterLocationInfoStruct locationInfo = null; + ChipStructs.ServiceAreaClusterAreaInfoStruct areaDesc = null; for (StructElement element: ((StructType)tlvValue).value()) { - if (element.contextTagNum() == LOCATION_I_D_ID) { + if (element.contextTagNum() == AREA_I_D_ID) { if (element.value(BaseTLVType.class).type() == TLVType.UInt) { UIntType castingValue = element.value(UIntType.class); - locationID = castingValue.value(Long.class); + areaID = castingValue.value(Long.class); } } else if (element.contextTagNum() == MAP_I_D_ID) { if (element.value(BaseTLVType.class).type() == TLVType.UInt) { UIntType castingValue = element.value(UIntType.class); mapID = castingValue.value(Integer.class); } - } else if (element.contextTagNum() == LOCATION_INFO_ID) { + } else if (element.contextTagNum() == AREA_DESC_ID) { if (element.value(BaseTLVType.class).type() == TLVType.Struct) { StructType castingValue = element.value(StructType.class); - locationInfo = ChipStructs.ServiceAreaClusterLocationInfoStruct.decodeTlv(castingValue); + areaDesc = ChipStructs.ServiceAreaClusterAreaInfoStruct.decodeTlv(castingValue); } } } - return new ServiceAreaClusterLocationStruct( - locationID, + return new ServiceAreaClusterAreaStruct( + areaID, mapID, - locationInfo + areaDesc ); } @Override public String toString() { StringBuilder output = new StringBuilder(); - output.append("ServiceAreaClusterLocationStruct {\n"); - output.append("\tlocationID: "); - output.append(locationID); + output.append("ServiceAreaClusterAreaStruct {\n"); + output.append("\tareaID: "); + output.append(areaID); output.append("\n"); output.append("\tmapID: "); output.append(mapID); output.append("\n"); - output.append("\tlocationInfo: "); - output.append(locationInfo); + output.append("\tareaDesc: "); + output.append(areaDesc); output.append("\n"); output.append("}\n"); return output.toString(); @@ -9400,22 +9400,22 @@ public String toString() { } } public static class ServiceAreaClusterProgressStruct { - public Long locationID; + public Long areaID; public Integer status; public @Nullable Optional totalOperationalTime; public @Nullable Optional estimatedTime; - private static final long LOCATION_I_D_ID = 0L; + private static final long AREA_I_D_ID = 0L; private static final long STATUS_ID = 1L; private static final long TOTAL_OPERATIONAL_TIME_ID = 2L; private static final long ESTIMATED_TIME_ID = 3L; public ServiceAreaClusterProgressStruct( - Long locationID, + Long areaID, Integer status, @Nullable Optional totalOperationalTime, @Nullable Optional estimatedTime ) { - this.locationID = locationID; + this.areaID = areaID; this.status = status; this.totalOperationalTime = totalOperationalTime; this.estimatedTime = estimatedTime; @@ -9423,7 +9423,7 @@ public ServiceAreaClusterProgressStruct( public StructType encodeTlv() { ArrayList values = new ArrayList<>(); - values.add(new StructElement(LOCATION_I_D_ID, new UIntType(locationID))); + values.add(new StructElement(AREA_I_D_ID, new UIntType(areaID))); values.add(new StructElement(STATUS_ID, new UIntType(status))); values.add(new StructElement(TOTAL_OPERATIONAL_TIME_ID, totalOperationalTime != null ? totalOperationalTime.map((nonOptionaltotalOperationalTime) -> new UIntType(nonOptionaltotalOperationalTime)).orElse(new EmptyType()) : new NullType())); values.add(new StructElement(ESTIMATED_TIME_ID, estimatedTime != null ? estimatedTime.map((nonOptionalestimatedTime) -> new UIntType(nonOptionalestimatedTime)).orElse(new EmptyType()) : new NullType())); @@ -9435,15 +9435,15 @@ public static ServiceAreaClusterProgressStruct decodeTlv(BaseTLVType tlvValue) { if (tlvValue == null || tlvValue.type() != TLVType.Struct) { return null; } - Long locationID = null; + Long areaID = null; Integer status = null; @Nullable Optional totalOperationalTime = null; @Nullable Optional estimatedTime = null; for (StructElement element: ((StructType)tlvValue).value()) { - if (element.contextTagNum() == LOCATION_I_D_ID) { + if (element.contextTagNum() == AREA_I_D_ID) { if (element.value(BaseTLVType.class).type() == TLVType.UInt) { UIntType castingValue = element.value(UIntType.class); - locationID = castingValue.value(Long.class); + areaID = castingValue.value(Long.class); } } else if (element.contextTagNum() == STATUS_ID) { if (element.value(BaseTLVType.class).type() == TLVType.UInt) { @@ -9463,7 +9463,7 @@ public static ServiceAreaClusterProgressStruct decodeTlv(BaseTLVType tlvValue) { } } return new ServiceAreaClusterProgressStruct( - locationID, + areaID, status, totalOperationalTime, estimatedTime @@ -9474,8 +9474,8 @@ public static ServiceAreaClusterProgressStruct decodeTlv(BaseTLVType tlvValue) { public String toString() { StringBuilder output = new StringBuilder(); output.append("ServiceAreaClusterProgressStruct {\n"); - output.append("\tlocationID: "); - output.append(locationID); + output.append("\tareaID: "); + output.append(areaID); output.append("\n"); output.append("\tstatus: "); output.append(status); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java index bad71209a40272..0f5e910682a659 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java @@ -11634,10 +11634,10 @@ public long getID() { } public enum Attribute { - SupportedLocations(0L), + SupportedAreas(0L), SupportedMaps(1L), - SelectedLocations(2L), - CurrentLocation(3L), + SelectedAreas(2L), + CurrentArea(3L), EstimatedEndTime(4L), Progress(5L), GeneratedCommandList(65528L), @@ -11686,8 +11686,8 @@ public static Event value(long id) throws NoSuchFieldError { } public enum Command { - SelectLocations(0L), - SkipCurrentLocation(2L),; + SelectAreas(0L), + SkipArea(2L),; private final long id; Command(long id) { this.id = id; @@ -11705,17 +11705,17 @@ public static Command value(long id) throws NoSuchFieldError { } throw new NoSuchFieldError(); } - }public enum SelectLocationsCommandField {NewLocations(0),; + }public enum SelectAreasCommandField {NewAreas(0),; private final int id; - SelectLocationsCommandField(int id) { + SelectAreasCommandField(int id) { this.id = id; } public int getID() { return id; } - public static SelectLocationsCommandField value(int id) throws NoSuchFieldError { - for (SelectLocationsCommandField field : SelectLocationsCommandField.values()) { + public static SelectAreasCommandField value(int id) throws NoSuchFieldError { + for (SelectAreasCommandField field : SelectAreasCommandField.values()) { if (field.getID() == id) { return field; } diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java index 1d398ff42e2c9d..44faa837ffff66 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java @@ -13117,7 +13117,7 @@ public void onError(Exception ex) { } - public static class DelegatedServiceAreaClusterSelectLocationsResponseCallback implements ChipClusters.ServiceAreaCluster.SelectLocationsResponseCallback, DelegatedClusterCallback { + public static class DelegatedServiceAreaClusterSelectAreasResponseCallback implements ChipClusters.ServiceAreaCluster.SelectAreasResponseCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @Override public void setCallbackDelegate(ClusterCommandCallback callback) { @@ -13141,7 +13141,7 @@ public void onError(Exception error) { } } - public static class DelegatedServiceAreaClusterSkipCurrentLocationResponseCallback implements ChipClusters.ServiceAreaCluster.SkipCurrentLocationResponseCallback, DelegatedClusterCallback { + public static class DelegatedServiceAreaClusterSkipAreaResponseCallback implements ChipClusters.ServiceAreaCluster.SkipAreaResponseCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @Override public void setCallbackDelegate(ClusterCommandCallback callback) { @@ -13164,7 +13164,7 @@ public void onError(Exception error) { callback.onFailure(error); } } - public static class DelegatedServiceAreaClusterSupportedLocationsAttributeCallback implements ChipClusters.ServiceAreaCluster.SupportedLocationsAttributeCallback, DelegatedClusterCallback { + public static class DelegatedServiceAreaClusterSupportedAreasAttributeCallback implements ChipClusters.ServiceAreaCluster.SupportedAreasAttributeCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @Override public void setCallbackDelegate(ClusterCommandCallback callback) { @@ -13172,9 +13172,9 @@ public void setCallbackDelegate(ClusterCommandCallback callback) { } @Override - public void onSuccess(List valueList) { + public void onSuccess(List valueList) { Map responseValues = new LinkedHashMap<>(); - CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); + CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); responseValues.put(commandResponseInfo, valueList); callback.onSuccess(responseValues); } @@ -13206,7 +13206,7 @@ public void onError(Exception ex) { } } - public static class DelegatedServiceAreaClusterSelectedLocationsAttributeCallback implements ChipClusters.ServiceAreaCluster.SelectedLocationsAttributeCallback, DelegatedClusterCallback { + public static class DelegatedServiceAreaClusterSelectedAreasAttributeCallback implements ChipClusters.ServiceAreaCluster.SelectedAreasAttributeCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @Override public void setCallbackDelegate(ClusterCommandCallback callback) { @@ -13227,7 +13227,7 @@ public void onError(Exception ex) { } } - public static class DelegatedServiceAreaClusterCurrentLocationAttributeCallback implements ChipClusters.ServiceAreaCluster.CurrentLocationAttributeCallback, DelegatedClusterCallback { + public static class DelegatedServiceAreaClusterCurrentAreaAttributeCallback implements ChipClusters.ServiceAreaCluster.CurrentAreaAttributeCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @Override public void setCallbackDelegate(ClusterCommandCallback callback) { @@ -26918,35 +26918,35 @@ public Map> getCommandMap() { Map serviceAreaClusterInteractionInfoMap = new LinkedHashMap<>(); - Map serviceAreaselectLocationsCommandParams = new LinkedHashMap(); + Map serviceAreaselectAreasCommandParams = new LinkedHashMap(); - CommandParameterInfo serviceAreaselectLocationsnewLocationsCommandParameterInfo = new CommandParameterInfo("newLocations", ArrayList.class, ArrayList.class); - serviceAreaselectLocationsCommandParams.put("newLocations",serviceAreaselectLocationsnewLocationsCommandParameterInfo); - InteractionInfo serviceAreaselectLocationsInteractionInfo = new InteractionInfo( + CommandParameterInfo serviceAreaselectAreasnewAreasCommandParameterInfo = new CommandParameterInfo("newAreas", ArrayList.class, ArrayList.class); + serviceAreaselectAreasCommandParams.put("newAreas",serviceAreaselectAreasnewAreasCommandParameterInfo); + InteractionInfo serviceAreaselectAreasInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { ((ChipClusters.ServiceAreaCluster) cluster) - .selectLocations((ChipClusters.ServiceAreaCluster.SelectLocationsResponseCallback) callback + .selectAreas((ChipClusters.ServiceAreaCluster.SelectAreasResponseCallback) callback , (ArrayList) - commandArguments.get("newLocations") + commandArguments.get("newAreas") ); }, - () -> new DelegatedServiceAreaClusterSelectLocationsResponseCallback(), - serviceAreaselectLocationsCommandParams + () -> new DelegatedServiceAreaClusterSelectAreasResponseCallback(), + serviceAreaselectAreasCommandParams ); - serviceAreaClusterInteractionInfoMap.put("selectLocations", serviceAreaselectLocationsInteractionInfo); + serviceAreaClusterInteractionInfoMap.put("selectAreas", serviceAreaselectAreasInteractionInfo); - Map serviceAreaskipCurrentLocationCommandParams = new LinkedHashMap(); - InteractionInfo serviceAreaskipCurrentLocationInteractionInfo = new InteractionInfo( + Map serviceAreaskipAreaCommandParams = new LinkedHashMap(); + InteractionInfo serviceAreaskipAreaInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { ((ChipClusters.ServiceAreaCluster) cluster) - .skipCurrentLocation((ChipClusters.ServiceAreaCluster.SkipCurrentLocationResponseCallback) callback + .skipArea((ChipClusters.ServiceAreaCluster.SkipAreaResponseCallback) callback ); }, - () -> new DelegatedServiceAreaClusterSkipCurrentLocationResponseCallback(), - serviceAreaskipCurrentLocationCommandParams + () -> new DelegatedServiceAreaClusterSkipAreaResponseCallback(), + serviceAreaskipAreaCommandParams ); - serviceAreaClusterInteractionInfoMap.put("skipCurrentLocation", serviceAreaskipCurrentLocationInteractionInfo); + serviceAreaClusterInteractionInfoMap.put("skipArea", serviceAreaskipAreaInteractionInfo); commandMap.put("serviceArea", serviceAreaClusterInteractionInfoMap); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java index 32d3d4f1a51756..64c2ae23902025 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java @@ -11863,17 +11863,17 @@ private static Map readBarrierControlInteractionInfo() return result; } private static Map readServiceAreaInteractionInfo() { - Map result = new LinkedHashMap<>();Map readServiceAreaSupportedLocationsCommandParams = new LinkedHashMap(); - InteractionInfo readServiceAreaSupportedLocationsAttributeInteractionInfo = new InteractionInfo( + Map result = new LinkedHashMap<>();Map readServiceAreaSupportedAreasCommandParams = new LinkedHashMap(); + InteractionInfo readServiceAreaSupportedAreasAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.ServiceAreaCluster) cluster).readSupportedLocationsAttribute( - (ChipClusters.ServiceAreaCluster.SupportedLocationsAttributeCallback) callback + ((ChipClusters.ServiceAreaCluster) cluster).readSupportedAreasAttribute( + (ChipClusters.ServiceAreaCluster.SupportedAreasAttributeCallback) callback ); }, - () -> new ClusterInfoMapping.DelegatedServiceAreaClusterSupportedLocationsAttributeCallback(), - readServiceAreaSupportedLocationsCommandParams + () -> new ClusterInfoMapping.DelegatedServiceAreaClusterSupportedAreasAttributeCallback(), + readServiceAreaSupportedAreasCommandParams ); - result.put("readSupportedLocationsAttribute", readServiceAreaSupportedLocationsAttributeInteractionInfo); + result.put("readSupportedAreasAttribute", readServiceAreaSupportedAreasAttributeInteractionInfo); Map readServiceAreaSupportedMapsCommandParams = new LinkedHashMap(); InteractionInfo readServiceAreaSupportedMapsAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { @@ -11885,28 +11885,28 @@ private static Map readServiceAreaInteractionInfo() { readServiceAreaSupportedMapsCommandParams ); result.put("readSupportedMapsAttribute", readServiceAreaSupportedMapsAttributeInteractionInfo); - Map readServiceAreaSelectedLocationsCommandParams = new LinkedHashMap(); - InteractionInfo readServiceAreaSelectedLocationsAttributeInteractionInfo = new InteractionInfo( + Map readServiceAreaSelectedAreasCommandParams = new LinkedHashMap(); + InteractionInfo readServiceAreaSelectedAreasAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.ServiceAreaCluster) cluster).readSelectedLocationsAttribute( - (ChipClusters.ServiceAreaCluster.SelectedLocationsAttributeCallback) callback + ((ChipClusters.ServiceAreaCluster) cluster).readSelectedAreasAttribute( + (ChipClusters.ServiceAreaCluster.SelectedAreasAttributeCallback) callback ); }, - () -> new ClusterInfoMapping.DelegatedServiceAreaClusterSelectedLocationsAttributeCallback(), - readServiceAreaSelectedLocationsCommandParams + () -> new ClusterInfoMapping.DelegatedServiceAreaClusterSelectedAreasAttributeCallback(), + readServiceAreaSelectedAreasCommandParams ); - result.put("readSelectedLocationsAttribute", readServiceAreaSelectedLocationsAttributeInteractionInfo); - Map readServiceAreaCurrentLocationCommandParams = new LinkedHashMap(); - InteractionInfo readServiceAreaCurrentLocationAttributeInteractionInfo = new InteractionInfo( + result.put("readSelectedAreasAttribute", readServiceAreaSelectedAreasAttributeInteractionInfo); + Map readServiceAreaCurrentAreaCommandParams = new LinkedHashMap(); + InteractionInfo readServiceAreaCurrentAreaAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { - ((ChipClusters.ServiceAreaCluster) cluster).readCurrentLocationAttribute( - (ChipClusters.ServiceAreaCluster.CurrentLocationAttributeCallback) callback + ((ChipClusters.ServiceAreaCluster) cluster).readCurrentAreaAttribute( + (ChipClusters.ServiceAreaCluster.CurrentAreaAttributeCallback) callback ); }, - () -> new ClusterInfoMapping.DelegatedServiceAreaClusterCurrentLocationAttributeCallback(), - readServiceAreaCurrentLocationCommandParams + () -> new ClusterInfoMapping.DelegatedServiceAreaClusterCurrentAreaAttributeCallback(), + readServiceAreaCurrentAreaCommandParams ); - result.put("readCurrentLocationAttribute", readServiceAreaCurrentLocationAttributeInteractionInfo); + result.put("readCurrentAreaAttribute", readServiceAreaCurrentAreaAttributeInteractionInfo); Map readServiceAreaEstimatedEndTimeCommandParams = new LinkedHashMap(); InteractionInfo readServiceAreaEstimatedEndTimeAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni index 3cbd5cb52ce17a..df66c2aa0e51aa 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni @@ -123,9 +123,9 @@ structs_sources = [ "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ScenesManagementClusterAttributeValuePairStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ScenesManagementClusterExtensionFieldSet.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ScenesManagementClusterSceneInfoStruct.kt", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterAreaInfoStruct.kt", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterAreaStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterLocationDescriptorStruct.kt", - "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterLocationInfoStruct.kt", - "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterLocationStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterMapStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterProgressStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/SoftwareDiagnosticsClusterThreadMetricsStruct.kt", diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterLocationInfoStruct.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterAreaInfoStruct.kt similarity index 92% rename from src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterLocationInfoStruct.kt rename to src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterAreaInfoStruct.kt index 3d3938fdbedf2b..e11d56110d37cf 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterLocationInfoStruct.kt +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterAreaInfoStruct.kt @@ -22,14 +22,14 @@ import matter.tlv.Tag import matter.tlv.TlvReader import matter.tlv.TlvWriter -class ServiceAreaClusterLocationInfoStruct( +class ServiceAreaClusterAreaInfoStruct( val locationInfo: ServiceAreaClusterLocationDescriptorStruct?, val landmarkTag: UInt?, val positionTag: UInt?, val surfaceTag: UInt?, ) { override fun toString(): String = buildString { - append("ServiceAreaClusterLocationInfoStruct {\n") + append("ServiceAreaClusterAreaInfoStruct {\n") append("\tlocationInfo : $locationInfo\n") append("\tlandmarkTag : $landmarkTag\n") append("\tpositionTag : $positionTag\n") @@ -70,7 +70,7 @@ class ServiceAreaClusterLocationInfoStruct( private const val TAG_POSITION_TAG = 2 private const val TAG_SURFACE_TAG = 3 - fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): ServiceAreaClusterLocationInfoStruct { + fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): ServiceAreaClusterAreaInfoStruct { tlvReader.enterStructure(tlvTag) val locationInfo = if (!tlvReader.isNull()) { @@ -106,12 +106,7 @@ class ServiceAreaClusterLocationInfoStruct( tlvReader.exitContainer() - return ServiceAreaClusterLocationInfoStruct( - locationInfo, - landmarkTag, - positionTag, - surfaceTag, - ) + return ServiceAreaClusterAreaInfoStruct(locationInfo, landmarkTag, positionTag, surfaceTag) } } } diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterLocationStruct.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterAreaStruct.kt similarity index 67% rename from src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterLocationStruct.kt rename to src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterAreaStruct.kt index f77ae437cad74c..74be0531c61dc5 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterLocationStruct.kt +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterAreaStruct.kt @@ -22,41 +22,41 @@ import matter.tlv.Tag import matter.tlv.TlvReader import matter.tlv.TlvWriter -class ServiceAreaClusterLocationStruct( - val locationID: ULong, +class ServiceAreaClusterAreaStruct( + val areaID: ULong, val mapID: UInt?, - val locationInfo: ServiceAreaClusterLocationInfoStruct, + val areaDesc: ServiceAreaClusterAreaInfoStruct, ) { override fun toString(): String = buildString { - append("ServiceAreaClusterLocationStruct {\n") - append("\tlocationID : $locationID\n") + append("ServiceAreaClusterAreaStruct {\n") + append("\tareaID : $areaID\n") append("\tmapID : $mapID\n") - append("\tlocationInfo : $locationInfo\n") + append("\tareaDesc : $areaDesc\n") append("}\n") } fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { tlvWriter.apply { startStructure(tlvTag) - put(ContextSpecificTag(TAG_LOCATION_I_D), locationID) + put(ContextSpecificTag(TAG_AREA_I_D), areaID) if (mapID != null) { put(ContextSpecificTag(TAG_MAP_I_D), mapID) } else { putNull(ContextSpecificTag(TAG_MAP_I_D)) } - locationInfo.toTlv(ContextSpecificTag(TAG_LOCATION_INFO), this) + areaDesc.toTlv(ContextSpecificTag(TAG_AREA_DESC), this) endStructure() } } companion object { - private const val TAG_LOCATION_I_D = 0 + private const val TAG_AREA_I_D = 0 private const val TAG_MAP_I_D = 1 - private const val TAG_LOCATION_INFO = 2 + private const val TAG_AREA_DESC = 2 - fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): ServiceAreaClusterLocationStruct { + fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): ServiceAreaClusterAreaStruct { tlvReader.enterStructure(tlvTag) - val locationID = tlvReader.getULong(ContextSpecificTag(TAG_LOCATION_I_D)) + val areaID = tlvReader.getULong(ContextSpecificTag(TAG_AREA_I_D)) val mapID = if (!tlvReader.isNull()) { tlvReader.getUInt(ContextSpecificTag(TAG_MAP_I_D)) @@ -64,15 +64,12 @@ class ServiceAreaClusterLocationStruct( tlvReader.getNull(ContextSpecificTag(TAG_MAP_I_D)) null } - val locationInfo = - ServiceAreaClusterLocationInfoStruct.fromTlv( - ContextSpecificTag(TAG_LOCATION_INFO), - tlvReader, - ) + val areaDesc = + ServiceAreaClusterAreaInfoStruct.fromTlv(ContextSpecificTag(TAG_AREA_DESC), tlvReader) tlvReader.exitContainer() - return ServiceAreaClusterLocationStruct(locationID, mapID, locationInfo) + return ServiceAreaClusterAreaStruct(areaID, mapID, areaDesc) } } } diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterProgressStruct.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterProgressStruct.kt index b601af531e103d..ddc8238168981d 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterProgressStruct.kt +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterProgressStruct.kt @@ -24,14 +24,14 @@ import matter.tlv.TlvReader import matter.tlv.TlvWriter class ServiceAreaClusterProgressStruct( - val locationID: ULong, + val areaID: ULong, val status: UInt, val totalOperationalTime: Optional?, val estimatedTime: Optional?, ) { override fun toString(): String = buildString { append("ServiceAreaClusterProgressStruct {\n") - append("\tlocationID : $locationID\n") + append("\tareaID : $areaID\n") append("\tstatus : $status\n") append("\ttotalOperationalTime : $totalOperationalTime\n") append("\testimatedTime : $estimatedTime\n") @@ -41,7 +41,7 @@ class ServiceAreaClusterProgressStruct( fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { tlvWriter.apply { startStructure(tlvTag) - put(ContextSpecificTag(TAG_LOCATION_I_D), locationID) + put(ContextSpecificTag(TAG_AREA_I_D), areaID) put(ContextSpecificTag(TAG_STATUS), status) if (totalOperationalTime != null) { if (totalOperationalTime.isPresent) { @@ -64,14 +64,14 @@ class ServiceAreaClusterProgressStruct( } companion object { - private const val TAG_LOCATION_I_D = 0 + private const val TAG_AREA_I_D = 0 private const val TAG_STATUS = 1 private const val TAG_TOTAL_OPERATIONAL_TIME = 2 private const val TAG_ESTIMATED_TIME = 3 fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): ServiceAreaClusterProgressStruct { tlvReader.enterStructure(tlvTag) - val locationID = tlvReader.getULong(ContextSpecificTag(TAG_LOCATION_I_D)) + val areaID = tlvReader.getULong(ContextSpecificTag(TAG_AREA_I_D)) val status = tlvReader.getUInt(ContextSpecificTag(TAG_STATUS)) val totalOperationalTime = if (!tlvReader.isNull()) { @@ -98,12 +98,7 @@ class ServiceAreaClusterProgressStruct( tlvReader.exitContainer() - return ServiceAreaClusterProgressStruct( - locationID, - status, - totalOperationalTime, - estimatedTime, - ) + return ServiceAreaClusterProgressStruct(areaID, status, totalOperationalTime, estimatedTime) } } } diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ServiceAreaCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ServiceAreaCluster.kt index 75e608837b40f0..3f7aad29ed5a42 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ServiceAreaCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ServiceAreaCluster.kt @@ -40,19 +40,19 @@ import matter.tlv.TlvReader import matter.tlv.TlvWriter class ServiceAreaCluster(private val controller: MatterController, private val endpointId: UShort) { - class SelectLocationsResponse(val status: UByte, val statusText: String?) + class SelectAreasResponse(val status: UByte, val statusText: String?) - class SkipCurrentLocationResponse(val status: UByte, val statusText: String?) + class SkipAreaResponse(val status: UByte, val statusText: String?) - class SupportedLocationsAttribute(val value: List) + class SupportedAreasAttribute(val value: List) - sealed class SupportedLocationsAttributeSubscriptionState { - data class Success(val value: List) : - SupportedLocationsAttributeSubscriptionState() + sealed class SupportedAreasAttributeSubscriptionState { + data class Success(val value: List) : + SupportedAreasAttributeSubscriptionState() - data class Error(val exception: Exception) : SupportedLocationsAttributeSubscriptionState() + data class Error(val exception: Exception) : SupportedAreasAttributeSubscriptionState() - object SubscriptionEstablished : SupportedLocationsAttributeSubscriptionState() + object SubscriptionEstablished : SupportedAreasAttributeSubscriptionState() } class SupportedMapsAttribute(val value: List?) @@ -66,24 +66,24 @@ class ServiceAreaCluster(private val controller: MatterController, private val e object SubscriptionEstablished : SupportedMapsAttributeSubscriptionState() } - class SelectedLocationsAttribute(val value: List?) + class SelectedAreasAttribute(val value: List?) - sealed class SelectedLocationsAttributeSubscriptionState { - data class Success(val value: List?) : SelectedLocationsAttributeSubscriptionState() + sealed class SelectedAreasAttributeSubscriptionState { + data class Success(val value: List?) : SelectedAreasAttributeSubscriptionState() - data class Error(val exception: Exception) : SelectedLocationsAttributeSubscriptionState() + data class Error(val exception: Exception) : SelectedAreasAttributeSubscriptionState() - object SubscriptionEstablished : SelectedLocationsAttributeSubscriptionState() + object SubscriptionEstablished : SelectedAreasAttributeSubscriptionState() } - class CurrentLocationAttribute(val value: UInt?) + class CurrentAreaAttribute(val value: UInt?) - sealed class CurrentLocationAttributeSubscriptionState { - data class Success(val value: UInt?) : CurrentLocationAttributeSubscriptionState() + sealed class CurrentAreaAttributeSubscriptionState { + data class Success(val value: UInt?) : CurrentAreaAttributeSubscriptionState() - data class Error(val exception: Exception) : CurrentLocationAttributeSubscriptionState() + data class Error(val exception: Exception) : CurrentAreaAttributeSubscriptionState() - object SubscriptionEstablished : CurrentLocationAttributeSubscriptionState() + object SubscriptionEstablished : CurrentAreaAttributeSubscriptionState() } class EstimatedEndTimeAttribute(val value: UInt?) @@ -147,19 +147,19 @@ class ServiceAreaCluster(private val controller: MatterController, private val e object SubscriptionEstablished : AttributeListAttributeSubscriptionState() } - suspend fun selectLocations( - newLocations: List?, + suspend fun selectAreas( + newAreas: List?, timedInvokeTimeout: Duration? = null, - ): SelectLocationsResponse { + ): SelectAreasResponse { val commandId: UInt = 0u val tlvWriter = TlvWriter() tlvWriter.startStructure(AnonymousTag) - val TAG_NEW_LOCATIONS_REQ: Int = 0 - newLocations?.let { - tlvWriter.startArray(ContextSpecificTag(TAG_NEW_LOCATIONS_REQ)) - for (item in newLocations.iterator()) { + val TAG_NEW_AREAS_REQ: Int = 0 + newAreas?.let { + tlvWriter.startArray(ContextSpecificTag(TAG_NEW_AREAS_REQ)) + for (item in newAreas.iterator()) { tlvWriter.put(AnonymousTag, item) } tlvWriter.endArray() @@ -214,12 +214,10 @@ class ServiceAreaCluster(private val controller: MatterController, private val e tlvReader.exitContainer() - return SelectLocationsResponse(status_decoded, statusText_decoded) + return SelectAreasResponse(status_decoded, statusText_decoded) } - suspend fun skipCurrentLocation( - timedInvokeTimeout: Duration? = null - ): SkipCurrentLocationResponse { + suspend fun skipArea(timedInvokeTimeout: Duration? = null): SkipAreaResponse { val commandId: UInt = 2u val tlvWriter = TlvWriter() @@ -274,10 +272,10 @@ class ServiceAreaCluster(private val controller: MatterController, private val e tlvReader.exitContainer() - return SkipCurrentLocationResponse(status_decoded, statusText_decoded) + return SkipAreaResponse(status_decoded, statusText_decoded) } - suspend fun readSupportedLocationsAttribute(): SupportedLocationsAttribute { + suspend fun readSupportedAreasAttribute(): SupportedAreasAttribute { val ATTRIBUTE_ID: UInt = 0u val attributePath = @@ -299,26 +297,26 @@ class ServiceAreaCluster(private val controller: MatterController, private val e it.path.attributeId == ATTRIBUTE_ID } - requireNotNull(attributeData) { "Supportedlocations attribute not found in response" } + requireNotNull(attributeData) { "Supportedareas attribute not found in response" } // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) - val decodedValue: List = - buildList { + val decodedValue: List = + buildList { tlvReader.enterArray(AnonymousTag) while (!tlvReader.isEndOfContainer()) { - add(ServiceAreaClusterLocationStruct.fromTlv(AnonymousTag, tlvReader)) + add(ServiceAreaClusterAreaStruct.fromTlv(AnonymousTag, tlvReader)) } tlvReader.exitContainer() } - return SupportedLocationsAttribute(decodedValue) + return SupportedAreasAttribute(decodedValue) } - suspend fun subscribeSupportedLocationsAttribute( + suspend fun subscribeSupportedAreasAttribute( minInterval: Int, maxInterval: Int, - ): Flow { + ): Flow { val ATTRIBUTE_ID: UInt = 0u val attributePaths = listOf( @@ -337,7 +335,7 @@ class ServiceAreaCluster(private val controller: MatterController, private val e when (subscriptionState) { is SubscriptionState.SubscriptionErrorNotification -> { emit( - SupportedLocationsAttributeSubscriptionState.Error( + SupportedAreasAttributeSubscriptionState.Error( Exception( "Subscription terminated with error code: ${subscriptionState.terminationCause}" ) @@ -351,24 +349,24 @@ class ServiceAreaCluster(private val controller: MatterController, private val e .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } requireNotNull(attributeData) { - "Supportedlocations attribute not found in Node State update" + "Supportedareas attribute not found in Node State update" } // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) - val decodedValue: List = - buildList { + val decodedValue: List = + buildList { tlvReader.enterArray(AnonymousTag) while (!tlvReader.isEndOfContainer()) { - add(ServiceAreaClusterLocationStruct.fromTlv(AnonymousTag, tlvReader)) + add(ServiceAreaClusterAreaStruct.fromTlv(AnonymousTag, tlvReader)) } tlvReader.exitContainer() } - emit(SupportedLocationsAttributeSubscriptionState.Success(decodedValue)) + emit(SupportedAreasAttributeSubscriptionState.Success(decodedValue)) } SubscriptionState.SubscriptionEstablished -> { - emit(SupportedLocationsAttributeSubscriptionState.SubscriptionEstablished) + emit(SupportedAreasAttributeSubscriptionState.SubscriptionEstablished) } } } @@ -479,7 +477,7 @@ class ServiceAreaCluster(private val controller: MatterController, private val e } } - suspend fun readSelectedLocationsAttribute(): SelectedLocationsAttribute { + suspend fun readSelectedAreasAttribute(): SelectedAreasAttribute { val ATTRIBUTE_ID: UInt = 2u val attributePath = @@ -501,7 +499,7 @@ class ServiceAreaCluster(private val controller: MatterController, private val e it.path.attributeId == ATTRIBUTE_ID } - requireNotNull(attributeData) { "Selectedlocations attribute not found in response" } + requireNotNull(attributeData) { "Selectedareas attribute not found in response" } // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) @@ -519,13 +517,13 @@ class ServiceAreaCluster(private val controller: MatterController, private val e null } - return SelectedLocationsAttribute(decodedValue) + return SelectedAreasAttribute(decodedValue) } - suspend fun subscribeSelectedLocationsAttribute( + suspend fun subscribeSelectedAreasAttribute( minInterval: Int, maxInterval: Int, - ): Flow { + ): Flow { val ATTRIBUTE_ID: UInt = 2u val attributePaths = listOf( @@ -544,7 +542,7 @@ class ServiceAreaCluster(private val controller: MatterController, private val e when (subscriptionState) { is SubscriptionState.SubscriptionErrorNotification -> { emit( - SelectedLocationsAttributeSubscriptionState.Error( + SelectedAreasAttributeSubscriptionState.Error( Exception( "Subscription terminated with error code: ${subscriptionState.terminationCause}" ) @@ -557,9 +555,7 @@ class ServiceAreaCluster(private val controller: MatterController, private val e .filterIsInstance() .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } - requireNotNull(attributeData) { - "Selectedlocations attribute not found in Node State update" - } + requireNotNull(attributeData) { "Selectedareas attribute not found in Node State update" } // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) @@ -577,16 +573,16 @@ class ServiceAreaCluster(private val controller: MatterController, private val e null } - decodedValue?.let { emit(SelectedLocationsAttributeSubscriptionState.Success(it)) } + decodedValue?.let { emit(SelectedAreasAttributeSubscriptionState.Success(it)) } } SubscriptionState.SubscriptionEstablished -> { - emit(SelectedLocationsAttributeSubscriptionState.SubscriptionEstablished) + emit(SelectedAreasAttributeSubscriptionState.SubscriptionEstablished) } } } } - suspend fun readCurrentLocationAttribute(): CurrentLocationAttribute { + suspend fun readCurrentAreaAttribute(): CurrentAreaAttribute { val ATTRIBUTE_ID: UInt = 3u val attributePath = @@ -608,7 +604,7 @@ class ServiceAreaCluster(private val controller: MatterController, private val e it.path.attributeId == ATTRIBUTE_ID } - requireNotNull(attributeData) { "Currentlocation attribute not found in response" } + requireNotNull(attributeData) { "Currentarea attribute not found in response" } // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) @@ -624,13 +620,13 @@ class ServiceAreaCluster(private val controller: MatterController, private val e null } - return CurrentLocationAttribute(decodedValue) + return CurrentAreaAttribute(decodedValue) } - suspend fun subscribeCurrentLocationAttribute( + suspend fun subscribeCurrentAreaAttribute( minInterval: Int, maxInterval: Int, - ): Flow { + ): Flow { val ATTRIBUTE_ID: UInt = 3u val attributePaths = listOf( @@ -649,7 +645,7 @@ class ServiceAreaCluster(private val controller: MatterController, private val e when (subscriptionState) { is SubscriptionState.SubscriptionErrorNotification -> { emit( - CurrentLocationAttributeSubscriptionState.Error( + CurrentAreaAttributeSubscriptionState.Error( Exception( "Subscription terminated with error code: ${subscriptionState.terminationCause}" ) @@ -662,9 +658,7 @@ class ServiceAreaCluster(private val controller: MatterController, private val e .filterIsInstance() .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } - requireNotNull(attributeData) { - "Currentlocation attribute not found in Node State update" - } + requireNotNull(attributeData) { "Currentarea attribute not found in Node State update" } // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) @@ -680,10 +674,10 @@ class ServiceAreaCluster(private val controller: MatterController, private val e null } - decodedValue?.let { emit(CurrentLocationAttributeSubscriptionState.Success(it)) } + decodedValue?.let { emit(CurrentAreaAttributeSubscriptionState.Success(it)) } } SubscriptionState.SubscriptionEstablished -> { - emit(CurrentLocationAttributeSubscriptionState.SubscriptionEstablished) + emit(CurrentAreaAttributeSubscriptionState.SubscriptionEstablished) } } } diff --git a/src/controller/java/generated/java/matter/controller/cluster/files.gni b/src/controller/java/generated/java/matter/controller/cluster/files.gni index 021d82d5e5b25a..31d51e53f76758 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/files.gni +++ b/src/controller/java/generated/java/matter/controller/cluster/files.gni @@ -123,9 +123,9 @@ matter_structs_sources = [ "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ScenesManagementClusterAttributeValuePairStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ScenesManagementClusterExtensionFieldSet.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ScenesManagementClusterSceneInfoStruct.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterAreaInfoStruct.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterAreaStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterLocationDescriptorStruct.kt", - "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterLocationInfoStruct.kt", - "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterLocationStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterMapStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterProgressStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/SoftwareDiagnosticsClusterThreadMetricsStruct.kt", diff --git a/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterLocationInfoStruct.kt b/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterAreaInfoStruct.kt similarity index 92% rename from src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterLocationInfoStruct.kt rename to src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterAreaInfoStruct.kt index d61927fb7ec852..a440d0b2ec4116 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterLocationInfoStruct.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterAreaInfoStruct.kt @@ -22,14 +22,14 @@ import matter.tlv.Tag import matter.tlv.TlvReader import matter.tlv.TlvWriter -class ServiceAreaClusterLocationInfoStruct( +class ServiceAreaClusterAreaInfoStruct( val locationInfo: ServiceAreaClusterLocationDescriptorStruct?, val landmarkTag: UByte?, val positionTag: UByte?, val surfaceTag: UByte?, ) { override fun toString(): String = buildString { - append("ServiceAreaClusterLocationInfoStruct {\n") + append("ServiceAreaClusterAreaInfoStruct {\n") append("\tlocationInfo : $locationInfo\n") append("\tlandmarkTag : $landmarkTag\n") append("\tpositionTag : $positionTag\n") @@ -70,7 +70,7 @@ class ServiceAreaClusterLocationInfoStruct( private const val TAG_POSITION_TAG = 2 private const val TAG_SURFACE_TAG = 3 - fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): ServiceAreaClusterLocationInfoStruct { + fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): ServiceAreaClusterAreaInfoStruct { tlvReader.enterStructure(tlvTag) val locationInfo = if (!tlvReader.isNull()) { @@ -106,12 +106,7 @@ class ServiceAreaClusterLocationInfoStruct( tlvReader.exitContainer() - return ServiceAreaClusterLocationInfoStruct( - locationInfo, - landmarkTag, - positionTag, - surfaceTag, - ) + return ServiceAreaClusterAreaInfoStruct(locationInfo, landmarkTag, positionTag, surfaceTag) } } } diff --git a/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterLocationStruct.kt b/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterAreaStruct.kt similarity index 67% rename from src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterLocationStruct.kt rename to src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterAreaStruct.kt index 42dc672d5c51fe..0ffdb8c9416d01 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterLocationStruct.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterAreaStruct.kt @@ -22,41 +22,41 @@ import matter.tlv.Tag import matter.tlv.TlvReader import matter.tlv.TlvWriter -class ServiceAreaClusterLocationStruct( - val locationID: UInt, +class ServiceAreaClusterAreaStruct( + val areaID: UInt, val mapID: UByte?, - val locationInfo: ServiceAreaClusterLocationInfoStruct, + val areaDesc: ServiceAreaClusterAreaInfoStruct, ) { override fun toString(): String = buildString { - append("ServiceAreaClusterLocationStruct {\n") - append("\tlocationID : $locationID\n") + append("ServiceAreaClusterAreaStruct {\n") + append("\tareaID : $areaID\n") append("\tmapID : $mapID\n") - append("\tlocationInfo : $locationInfo\n") + append("\tareaDesc : $areaDesc\n") append("}\n") } fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { tlvWriter.apply { startStructure(tlvTag) - put(ContextSpecificTag(TAG_LOCATION_I_D), locationID) + put(ContextSpecificTag(TAG_AREA_I_D), areaID) if (mapID != null) { put(ContextSpecificTag(TAG_MAP_I_D), mapID) } else { putNull(ContextSpecificTag(TAG_MAP_I_D)) } - locationInfo.toTlv(ContextSpecificTag(TAG_LOCATION_INFO), this) + areaDesc.toTlv(ContextSpecificTag(TAG_AREA_DESC), this) endStructure() } } companion object { - private const val TAG_LOCATION_I_D = 0 + private const val TAG_AREA_I_D = 0 private const val TAG_MAP_I_D = 1 - private const val TAG_LOCATION_INFO = 2 + private const val TAG_AREA_DESC = 2 - fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): ServiceAreaClusterLocationStruct { + fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): ServiceAreaClusterAreaStruct { tlvReader.enterStructure(tlvTag) - val locationID = tlvReader.getUInt(ContextSpecificTag(TAG_LOCATION_I_D)) + val areaID = tlvReader.getUInt(ContextSpecificTag(TAG_AREA_I_D)) val mapID = if (!tlvReader.isNull()) { tlvReader.getUByte(ContextSpecificTag(TAG_MAP_I_D)) @@ -64,15 +64,12 @@ class ServiceAreaClusterLocationStruct( tlvReader.getNull(ContextSpecificTag(TAG_MAP_I_D)) null } - val locationInfo = - ServiceAreaClusterLocationInfoStruct.fromTlv( - ContextSpecificTag(TAG_LOCATION_INFO), - tlvReader, - ) + val areaDesc = + ServiceAreaClusterAreaInfoStruct.fromTlv(ContextSpecificTag(TAG_AREA_DESC), tlvReader) tlvReader.exitContainer() - return ServiceAreaClusterLocationStruct(locationID, mapID, locationInfo) + return ServiceAreaClusterAreaStruct(areaID, mapID, areaDesc) } } } diff --git a/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterProgressStruct.kt b/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterProgressStruct.kt index 3dd3eb1e412260..4421bb606a7466 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterProgressStruct.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterProgressStruct.kt @@ -24,14 +24,14 @@ import matter.tlv.TlvReader import matter.tlv.TlvWriter class ServiceAreaClusterProgressStruct( - val locationID: UInt, + val areaID: UInt, val status: UByte, val totalOperationalTime: Optional?, val estimatedTime: Optional?, ) { override fun toString(): String = buildString { append("ServiceAreaClusterProgressStruct {\n") - append("\tlocationID : $locationID\n") + append("\tareaID : $areaID\n") append("\tstatus : $status\n") append("\ttotalOperationalTime : $totalOperationalTime\n") append("\testimatedTime : $estimatedTime\n") @@ -41,7 +41,7 @@ class ServiceAreaClusterProgressStruct( fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { tlvWriter.apply { startStructure(tlvTag) - put(ContextSpecificTag(TAG_LOCATION_I_D), locationID) + put(ContextSpecificTag(TAG_AREA_I_D), areaID) put(ContextSpecificTag(TAG_STATUS), status) if (totalOperationalTime != null) { if (totalOperationalTime.isPresent) { @@ -64,14 +64,14 @@ class ServiceAreaClusterProgressStruct( } companion object { - private const val TAG_LOCATION_I_D = 0 + private const val TAG_AREA_I_D = 0 private const val TAG_STATUS = 1 private const val TAG_TOTAL_OPERATIONAL_TIME = 2 private const val TAG_ESTIMATED_TIME = 3 fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): ServiceAreaClusterProgressStruct { tlvReader.enterStructure(tlvTag) - val locationID = tlvReader.getUInt(ContextSpecificTag(TAG_LOCATION_I_D)) + val areaID = tlvReader.getUInt(ContextSpecificTag(TAG_AREA_I_D)) val status = tlvReader.getUByte(ContextSpecificTag(TAG_STATUS)) val totalOperationalTime = if (!tlvReader.isNull()) { @@ -98,12 +98,7 @@ class ServiceAreaClusterProgressStruct( tlvReader.exitContainer() - return ServiceAreaClusterProgressStruct( - locationID, - status, - totalOperationalTime, - estimatedTime, - ) + return ServiceAreaClusterProgressStruct(areaID, status, totalOperationalTime, estimatedTime) } } } diff --git a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp index 81e24a4bc9dcd7..090428ca3fe7eb 100644 --- a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp @@ -28610,8 +28610,8 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR using namespace app::Clusters::ServiceArea; switch (aPath.mAttributeId) { - case Attributes::SupportedLocations::Id: { - using TypeInfo = Attributes::SupportedLocations::TypeInfo; + case Attributes::SupportedAreas::Id: { + using TypeInfo = Attributes::SupportedAreas::TypeInfo; TypeInfo::DecodableType cppValue; *aError = app::DataModel::Decode(aReader, cppValue); if (*aError != CHIP_NO_ERROR) @@ -28626,13 +28626,13 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR { auto & entry_0 = iter_value_0.GetValue(); jobject newElement_0; - jobject newElement_0_locationID; - std::string newElement_0_locationIDClassName = "java/lang/Long"; - std::string newElement_0_locationIDCtorSignature = "(J)V"; - jlong jninewElement_0_locationID = static_cast(entry_0.locationID); - chip::JniReferences::GetInstance().CreateBoxedObject(newElement_0_locationIDClassName.c_str(), - newElement_0_locationIDCtorSignature.c_str(), - jninewElement_0_locationID, newElement_0_locationID); + jobject newElement_0_areaID; + std::string newElement_0_areaIDClassName = "java/lang/Long"; + std::string newElement_0_areaIDCtorSignature = "(J)V"; + jlong jninewElement_0_areaID = static_cast(entry_0.areaID); + chip::JniReferences::GetInstance().CreateBoxedObject(newElement_0_areaIDClassName.c_str(), + newElement_0_areaIDCtorSignature.c_str(), + jninewElement_0_areaID, newElement_0_areaID); jobject newElement_0_mapID; if (entry_0.mapID.IsNull()) { @@ -28647,50 +28647,48 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR newElement_0_mapIDCtorSignature.c_str(), jninewElement_0_mapID, newElement_0_mapID); } - jobject newElement_0_locationInfo; - jobject newElement_0_locationInfo_locationInfo; - if (entry_0.locationInfo.locationInfo.IsNull()) + jobject newElement_0_areaDesc; + jobject newElement_0_areaDesc_locationInfo; + if (entry_0.areaDesc.locationInfo.IsNull()) { - newElement_0_locationInfo_locationInfo = nullptr; + newElement_0_areaDesc_locationInfo = nullptr; } else { - jobject newElement_0_locationInfo_locationInfo_locationName; - LogErrorOnFailure( - chip::JniReferences::GetInstance().CharToStringUTF(entry_0.locationInfo.locationInfo.Value().locationName, - newElement_0_locationInfo_locationInfo_locationName)); - jobject newElement_0_locationInfo_locationInfo_floorNumber; - if (entry_0.locationInfo.locationInfo.Value().floorNumber.IsNull()) + jobject newElement_0_areaDesc_locationInfo_locationName; + LogErrorOnFailure(chip::JniReferences::GetInstance().CharToStringUTF( + entry_0.areaDesc.locationInfo.Value().locationName, newElement_0_areaDesc_locationInfo_locationName)); + jobject newElement_0_areaDesc_locationInfo_floorNumber; + if (entry_0.areaDesc.locationInfo.Value().floorNumber.IsNull()) { - newElement_0_locationInfo_locationInfo_floorNumber = nullptr; + newElement_0_areaDesc_locationInfo_floorNumber = nullptr; } else { - std::string newElement_0_locationInfo_locationInfo_floorNumberClassName = "java/lang/Integer"; - std::string newElement_0_locationInfo_locationInfo_floorNumberCtorSignature = "(I)V"; - jint jninewElement_0_locationInfo_locationInfo_floorNumber = - static_cast(entry_0.locationInfo.locationInfo.Value().floorNumber.Value()); + std::string newElement_0_areaDesc_locationInfo_floorNumberClassName = "java/lang/Integer"; + std::string newElement_0_areaDesc_locationInfo_floorNumberCtorSignature = "(I)V"; + jint jninewElement_0_areaDesc_locationInfo_floorNumber = + static_cast(entry_0.areaDesc.locationInfo.Value().floorNumber.Value()); chip::JniReferences::GetInstance().CreateBoxedObject( - newElement_0_locationInfo_locationInfo_floorNumberClassName.c_str(), - newElement_0_locationInfo_locationInfo_floorNumberCtorSignature.c_str(), - jninewElement_0_locationInfo_locationInfo_floorNumber, - newElement_0_locationInfo_locationInfo_floorNumber); + newElement_0_areaDesc_locationInfo_floorNumberClassName.c_str(), + newElement_0_areaDesc_locationInfo_floorNumberCtorSignature.c_str(), + jninewElement_0_areaDesc_locationInfo_floorNumber, newElement_0_areaDesc_locationInfo_floorNumber); } - jobject newElement_0_locationInfo_locationInfo_areaType; - if (entry_0.locationInfo.locationInfo.Value().areaType.IsNull()) + jobject newElement_0_areaDesc_locationInfo_areaType; + if (entry_0.areaDesc.locationInfo.Value().areaType.IsNull()) { - newElement_0_locationInfo_locationInfo_areaType = nullptr; + newElement_0_areaDesc_locationInfo_areaType = nullptr; } else { - std::string newElement_0_locationInfo_locationInfo_areaTypeClassName = "java/lang/Integer"; - std::string newElement_0_locationInfo_locationInfo_areaTypeCtorSignature = "(I)V"; - jint jninewElement_0_locationInfo_locationInfo_areaType = - static_cast(entry_0.locationInfo.locationInfo.Value().areaType.Value()); + std::string newElement_0_areaDesc_locationInfo_areaTypeClassName = "java/lang/Integer"; + std::string newElement_0_areaDesc_locationInfo_areaTypeCtorSignature = "(I)V"; + jint jninewElement_0_areaDesc_locationInfo_areaType = + static_cast(entry_0.areaDesc.locationInfo.Value().areaType.Value()); chip::JniReferences::GetInstance().CreateBoxedObject( - newElement_0_locationInfo_locationInfo_areaTypeClassName.c_str(), - newElement_0_locationInfo_locationInfo_areaTypeCtorSignature.c_str(), - jninewElement_0_locationInfo_locationInfo_areaType, newElement_0_locationInfo_locationInfo_areaType); + newElement_0_areaDesc_locationInfo_areaTypeClassName.c_str(), + newElement_0_areaDesc_locationInfo_areaTypeCtorSignature.c_str(), + jninewElement_0_areaDesc_locationInfo_areaType, newElement_0_areaDesc_locationInfo_areaType); } jclass locationDescriptorStructStructClass_4; @@ -28713,105 +28711,101 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR return nullptr; } - newElement_0_locationInfo_locationInfo = env->NewObject( - locationDescriptorStructStructClass_4, locationDescriptorStructStructCtor_4, - newElement_0_locationInfo_locationInfo_locationName, newElement_0_locationInfo_locationInfo_floorNumber, - newElement_0_locationInfo_locationInfo_areaType); + newElement_0_areaDesc_locationInfo = + env->NewObject(locationDescriptorStructStructClass_4, locationDescriptorStructStructCtor_4, + newElement_0_areaDesc_locationInfo_locationName, + newElement_0_areaDesc_locationInfo_floorNumber, newElement_0_areaDesc_locationInfo_areaType); } - jobject newElement_0_locationInfo_landmarkTag; - if (entry_0.locationInfo.landmarkTag.IsNull()) + jobject newElement_0_areaDesc_landmarkTag; + if (entry_0.areaDesc.landmarkTag.IsNull()) { - newElement_0_locationInfo_landmarkTag = nullptr; + newElement_0_areaDesc_landmarkTag = nullptr; } else { - std::string newElement_0_locationInfo_landmarkTagClassName = "java/lang/Integer"; - std::string newElement_0_locationInfo_landmarkTagCtorSignature = "(I)V"; - jint jninewElement_0_locationInfo_landmarkTag = static_cast(entry_0.locationInfo.landmarkTag.Value()); + std::string newElement_0_areaDesc_landmarkTagClassName = "java/lang/Integer"; + std::string newElement_0_areaDesc_landmarkTagCtorSignature = "(I)V"; + jint jninewElement_0_areaDesc_landmarkTag = static_cast(entry_0.areaDesc.landmarkTag.Value()); chip::JniReferences::GetInstance().CreateBoxedObject( - newElement_0_locationInfo_landmarkTagClassName.c_str(), - newElement_0_locationInfo_landmarkTagCtorSignature.c_str(), jninewElement_0_locationInfo_landmarkTag, - newElement_0_locationInfo_landmarkTag); + newElement_0_areaDesc_landmarkTagClassName.c_str(), newElement_0_areaDesc_landmarkTagCtorSignature.c_str(), + jninewElement_0_areaDesc_landmarkTag, newElement_0_areaDesc_landmarkTag); } - jobject newElement_0_locationInfo_positionTag; - if (entry_0.locationInfo.positionTag.IsNull()) + jobject newElement_0_areaDesc_positionTag; + if (entry_0.areaDesc.positionTag.IsNull()) { - newElement_0_locationInfo_positionTag = nullptr; + newElement_0_areaDesc_positionTag = nullptr; } else { - std::string newElement_0_locationInfo_positionTagClassName = "java/lang/Integer"; - std::string newElement_0_locationInfo_positionTagCtorSignature = "(I)V"; - jint jninewElement_0_locationInfo_positionTag = static_cast(entry_0.locationInfo.positionTag.Value()); + std::string newElement_0_areaDesc_positionTagClassName = "java/lang/Integer"; + std::string newElement_0_areaDesc_positionTagCtorSignature = "(I)V"; + jint jninewElement_0_areaDesc_positionTag = static_cast(entry_0.areaDesc.positionTag.Value()); chip::JniReferences::GetInstance().CreateBoxedObject( - newElement_0_locationInfo_positionTagClassName.c_str(), - newElement_0_locationInfo_positionTagCtorSignature.c_str(), jninewElement_0_locationInfo_positionTag, - newElement_0_locationInfo_positionTag); + newElement_0_areaDesc_positionTagClassName.c_str(), newElement_0_areaDesc_positionTagCtorSignature.c_str(), + jninewElement_0_areaDesc_positionTag, newElement_0_areaDesc_positionTag); } - jobject newElement_0_locationInfo_surfaceTag; - if (entry_0.locationInfo.surfaceTag.IsNull()) + jobject newElement_0_areaDesc_surfaceTag; + if (entry_0.areaDesc.surfaceTag.IsNull()) { - newElement_0_locationInfo_surfaceTag = nullptr; + newElement_0_areaDesc_surfaceTag = nullptr; } else { - std::string newElement_0_locationInfo_surfaceTagClassName = "java/lang/Integer"; - std::string newElement_0_locationInfo_surfaceTagCtorSignature = "(I)V"; - jint jninewElement_0_locationInfo_surfaceTag = static_cast(entry_0.locationInfo.surfaceTag.Value()); + std::string newElement_0_areaDesc_surfaceTagClassName = "java/lang/Integer"; + std::string newElement_0_areaDesc_surfaceTagCtorSignature = "(I)V"; + jint jninewElement_0_areaDesc_surfaceTag = static_cast(entry_0.areaDesc.surfaceTag.Value()); chip::JniReferences::GetInstance().CreateBoxedObject( - newElement_0_locationInfo_surfaceTagClassName.c_str(), - newElement_0_locationInfo_surfaceTagCtorSignature.c_str(), jninewElement_0_locationInfo_surfaceTag, - newElement_0_locationInfo_surfaceTag); + newElement_0_areaDesc_surfaceTagClassName.c_str(), newElement_0_areaDesc_surfaceTagCtorSignature.c_str(), + jninewElement_0_areaDesc_surfaceTag, newElement_0_areaDesc_surfaceTag); } - jclass locationInfoStructStructClass_2; + jclass areaInfoStructStructClass_2; err = chip::JniReferences::GetInstance().GetLocalClassRef( - env, "chip/devicecontroller/ChipStructs$ServiceAreaClusterLocationInfoStruct", locationInfoStructStructClass_2); + env, "chip/devicecontroller/ChipStructs$ServiceAreaClusterAreaInfoStruct", areaInfoStructStructClass_2); if (err != CHIP_NO_ERROR) { - ChipLogError(Zcl, "Could not find class ChipStructs$ServiceAreaClusterLocationInfoStruct"); + ChipLogError(Zcl, "Could not find class ChipStructs$ServiceAreaClusterAreaInfoStruct"); return nullptr; } - jmethodID locationInfoStructStructCtor_2; + jmethodID areaInfoStructStructCtor_2; err = chip::JniReferences::GetInstance().FindMethod( - env, locationInfoStructStructClass_2, "", + env, areaInfoStructStructClass_2, "", "(Lchip/devicecontroller/ChipStructs$ServiceAreaClusterLocationDescriptorStruct;Ljava/lang/Integer;Ljava/lang/" "Integer;Ljava/lang/Integer;)V", - &locationInfoStructStructCtor_2); - if (err != CHIP_NO_ERROR || locationInfoStructStructCtor_2 == nullptr) + &areaInfoStructStructCtor_2); + if (err != CHIP_NO_ERROR || areaInfoStructStructCtor_2 == nullptr) { - ChipLogError(Zcl, "Could not find ChipStructs$ServiceAreaClusterLocationInfoStruct constructor"); + ChipLogError(Zcl, "Could not find ChipStructs$ServiceAreaClusterAreaInfoStruct constructor"); return nullptr; } - newElement_0_locationInfo = - env->NewObject(locationInfoStructStructClass_2, locationInfoStructStructCtor_2, - newElement_0_locationInfo_locationInfo, newElement_0_locationInfo_landmarkTag, - newElement_0_locationInfo_positionTag, newElement_0_locationInfo_surfaceTag); + newElement_0_areaDesc = env->NewObject(areaInfoStructStructClass_2, areaInfoStructStructCtor_2, + newElement_0_areaDesc_locationInfo, newElement_0_areaDesc_landmarkTag, + newElement_0_areaDesc_positionTag, newElement_0_areaDesc_surfaceTag); - jclass locationStructStructClass_1; + jclass areaStructStructClass_1; err = chip::JniReferences::GetInstance().GetLocalClassRef( - env, "chip/devicecontroller/ChipStructs$ServiceAreaClusterLocationStruct", locationStructStructClass_1); + env, "chip/devicecontroller/ChipStructs$ServiceAreaClusterAreaStruct", areaStructStructClass_1); if (err != CHIP_NO_ERROR) { - ChipLogError(Zcl, "Could not find class ChipStructs$ServiceAreaClusterLocationStruct"); + ChipLogError(Zcl, "Could not find class ChipStructs$ServiceAreaClusterAreaStruct"); return nullptr; } - jmethodID locationStructStructCtor_1; - err = chip::JniReferences::GetInstance().FindMethod(env, locationStructStructClass_1, "", - "(Ljava/lang/Long;Ljava/lang/Integer;Lchip/devicecontroller/" - "ChipStructs$ServiceAreaClusterLocationInfoStruct;)V", - &locationStructStructCtor_1); - if (err != CHIP_NO_ERROR || locationStructStructCtor_1 == nullptr) + jmethodID areaStructStructCtor_1; + err = chip::JniReferences::GetInstance().FindMethod( + env, areaStructStructClass_1, "", + "(Ljava/lang/Long;Ljava/lang/Integer;Lchip/devicecontroller/ChipStructs$ServiceAreaClusterAreaInfoStruct;)V", + &areaStructStructCtor_1); + if (err != CHIP_NO_ERROR || areaStructStructCtor_1 == nullptr) { - ChipLogError(Zcl, "Could not find ChipStructs$ServiceAreaClusterLocationStruct constructor"); + ChipLogError(Zcl, "Could not find ChipStructs$ServiceAreaClusterAreaStruct constructor"); return nullptr; } - newElement_0 = env->NewObject(locationStructStructClass_1, locationStructStructCtor_1, newElement_0_locationID, - newElement_0_mapID, newElement_0_locationInfo); + newElement_0 = env->NewObject(areaStructStructClass_1, areaStructStructCtor_1, newElement_0_areaID, + newElement_0_mapID, newElement_0_areaDesc); chip::JniReferences::GetInstance().AddToList(value, newElement_0); } return value; @@ -28873,8 +28867,8 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR } return value; } - case Attributes::SelectedLocations::Id: { - using TypeInfo = Attributes::SelectedLocations::TypeInfo; + case Attributes::SelectedAreas::Id: { + using TypeInfo = Attributes::SelectedAreas::TypeInfo; TypeInfo::DecodableType cppValue; *aError = app::DataModel::Decode(aReader, cppValue); if (*aError != CHIP_NO_ERROR) @@ -28905,8 +28899,8 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR } return value; } - case Attributes::CurrentLocation::Id: { - using TypeInfo = Attributes::CurrentLocation::TypeInfo; + case Attributes::CurrentArea::Id: { + using TypeInfo = Attributes::CurrentArea::TypeInfo; TypeInfo::DecodableType cppValue; *aError = app::DataModel::Decode(aReader, cppValue); if (*aError != CHIP_NO_ERROR) @@ -28973,13 +28967,13 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR { auto & entry_1 = iter_value_1.GetValue(); jobject newElement_1; - jobject newElement_1_locationID; - std::string newElement_1_locationIDClassName = "java/lang/Long"; - std::string newElement_1_locationIDCtorSignature = "(J)V"; - jlong jninewElement_1_locationID = static_cast(entry_1.locationID); - chip::JniReferences::GetInstance().CreateBoxedObject( - newElement_1_locationIDClassName.c_str(), newElement_1_locationIDCtorSignature.c_str(), - jninewElement_1_locationID, newElement_1_locationID); + jobject newElement_1_areaID; + std::string newElement_1_areaIDClassName = "java/lang/Long"; + std::string newElement_1_areaIDCtorSignature = "(J)V"; + jlong jninewElement_1_areaID = static_cast(entry_1.areaID); + chip::JniReferences::GetInstance().CreateBoxedObject(newElement_1_areaIDClassName.c_str(), + newElement_1_areaIDCtorSignature.c_str(), + jninewElement_1_areaID, newElement_1_areaID); jobject newElement_1_status; std::string newElement_1_statusClassName = "java/lang/Integer"; std::string newElement_1_statusCtorSignature = "(I)V"; @@ -29062,7 +29056,7 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR } newElement_1 = - env->NewObject(progressStructStructClass_2, progressStructStructCtor_2, newElement_1_locationID, + env->NewObject(progressStructStructClass_2, progressStructStructCtor_2, newElement_1_areaID, newElement_1_status, newElement_1_totalOperationalTime, newElement_1_estimatedTime); chip::JniReferences::GetInstance().AddToList(value, newElement_1); } diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index 5ab0ac895b659b..c8fe72913b6b67 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -8562,21 +8562,21 @@ class ChipClusters: "commands": { 0x00000000: { "commandId": 0x00000000, - "commandName": "SelectLocations", + "commandName": "SelectAreas", "args": { - "newLocations": "int", + "newAreas": "int", }, }, 0x00000002: { "commandId": 0x00000002, - "commandName": "SkipCurrentLocation", + "commandName": "SkipArea", "args": { }, }, }, "attributes": { 0x00000000: { - "attributeName": "SupportedLocations", + "attributeName": "SupportedAreas", "attributeId": 0x00000000, "type": "", "reportable": True, @@ -8588,13 +8588,13 @@ class ChipClusters: "reportable": True, }, 0x00000002: { - "attributeName": "SelectedLocations", + "attributeName": "SelectedAreas", "attributeId": 0x00000002, "type": "int", "reportable": True, }, 0x00000003: { - "attributeName": "CurrentLocation", + "attributeName": "CurrentArea", "attributeId": 0x00000003, "type": "int", "reportable": True, diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 1a110f1bc09b74..72364de4be6410 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -31113,10 +31113,10 @@ class ServiceArea(Cluster): def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="supportedLocations", Tag=0x00000000, Type=typing.List[ServiceArea.Structs.LocationStruct]), + ClusterObjectFieldDescriptor(Label="supportedAreas", Tag=0x00000000, Type=typing.List[ServiceArea.Structs.AreaStruct]), ClusterObjectFieldDescriptor(Label="supportedMaps", Tag=0x00000001, Type=typing.Union[Nullable, typing.List[ServiceArea.Structs.MapStruct]]), - ClusterObjectFieldDescriptor(Label="selectedLocations", Tag=0x00000002, Type=typing.Union[Nullable, typing.List[uint]]), - ClusterObjectFieldDescriptor(Label="currentLocation", Tag=0x00000003, Type=typing.Union[None, Nullable, uint]), + ClusterObjectFieldDescriptor(Label="selectedAreas", Tag=0x00000002, Type=typing.Union[Nullable, typing.List[uint]]), + ClusterObjectFieldDescriptor(Label="currentArea", Tag=0x00000003, Type=typing.Union[None, Nullable, uint]), ClusterObjectFieldDescriptor(Label="estimatedEndTime", Tag=0x00000004, Type=typing.Union[None, Nullable, uint]), ClusterObjectFieldDescriptor(Label="progress", Tag=0x00000005, Type=typing.Union[None, Nullable, typing.List[ServiceArea.Structs.ProgressStruct]]), ClusterObjectFieldDescriptor(Label="generatedCommandList", Tag=0x0000FFF8, Type=typing.List[uint]), @@ -31127,10 +31127,10 @@ def descriptor(cls) -> ClusterObjectDescriptor: ClusterObjectFieldDescriptor(Label="clusterRevision", Tag=0x0000FFFD, Type=uint), ]) - supportedLocations: 'typing.List[ServiceArea.Structs.LocationStruct]' = None + supportedAreas: 'typing.List[ServiceArea.Structs.AreaStruct]' = None supportedMaps: 'typing.Union[Nullable, typing.List[ServiceArea.Structs.MapStruct]]' = None - selectedLocations: 'typing.Union[Nullable, typing.List[uint]]' = None - currentLocation: 'typing.Union[None, Nullable, uint]' = None + selectedAreas: 'typing.Union[Nullable, typing.List[uint]]' = None + currentArea: 'typing.Union[None, Nullable, uint]' = None estimatedEndTime: 'typing.Union[None, Nullable, uint]' = None progress: 'typing.Union[None, Nullable, typing.List[ServiceArea.Structs.ProgressStruct]]' = None generatedCommandList: 'typing.List[uint]' = None @@ -31152,10 +31152,10 @@ class OperationalStatusEnum(MatterIntEnum): # enum value. This specific value should never be transmitted. kUnknownEnumValue = 4, - class SelectLocationsStatus(MatterIntEnum): + class SelectAreasStatus(MatterIntEnum): kSuccess = 0x00 - kUnsupportedLocation = 0x01 - kDuplicatedLocations = 0x02 + kUnsupportedArea = 0x01 + kDuplicatedAreas = 0x02 kInvalidInMode = 0x03 kInvalidSet = 0x04 # All received enum values that are not listed above will be mapped @@ -31164,9 +31164,9 @@ class SelectLocationsStatus(MatterIntEnum): # enum value. This specific value should never be transmitted. kUnknownEnumValue = 5, - class SkipCurrentLocationStatus(MatterIntEnum): + class SkipAreaStatus(MatterIntEnum): kSuccess = 0x00 - kInvalidLocationList = 0x01 + kInvalidAreaList = 0x01 kInvalidInMode = 0x02 # All received enum values that are not listed above will be mapped # to kUnknownEnumValue. This is a helper enum value that should only @@ -31181,7 +31181,7 @@ class Feature(IntFlag): class Structs: @dataclass - class LocationInfoStruct(ClusterObject): + class AreaInfoStruct(ClusterObject): @ChipUtility.classproperty def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( @@ -31198,19 +31198,19 @@ def descriptor(cls) -> ClusterObjectDescriptor: surfaceTag: 'typing.Union[Nullable, Globals.Enums.FloorSurfaceTag]' = NullValue @dataclass - class LocationStruct(ClusterObject): + class AreaStruct(ClusterObject): @ChipUtility.classproperty def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="locationID", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="areaID", Tag=0, Type=uint), ClusterObjectFieldDescriptor(Label="mapID", Tag=1, Type=typing.Union[Nullable, uint]), - ClusterObjectFieldDescriptor(Label="locationInfo", Tag=2, Type=ServiceArea.Structs.LocationInfoStruct), + ClusterObjectFieldDescriptor(Label="areaDesc", Tag=2, Type=ServiceArea.Structs.AreaInfoStruct), ]) - locationID: 'uint' = 0 + areaID: 'uint' = 0 mapID: 'typing.Union[Nullable, uint]' = NullValue - locationInfo: 'ServiceArea.Structs.LocationInfoStruct' = field(default_factory=lambda: ServiceArea.Structs.LocationInfoStruct()) + areaDesc: 'ServiceArea.Structs.AreaInfoStruct' = field(default_factory=lambda: ServiceArea.Structs.AreaInfoStruct()) @dataclass class MapStruct(ClusterObject): @@ -31231,36 +31231,36 @@ class ProgressStruct(ClusterObject): def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="locationID", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="areaID", Tag=0, Type=uint), ClusterObjectFieldDescriptor(Label="status", Tag=1, Type=ServiceArea.Enums.OperationalStatusEnum), ClusterObjectFieldDescriptor(Label="totalOperationalTime", Tag=2, Type=typing.Union[None, Nullable, uint]), ClusterObjectFieldDescriptor(Label="estimatedTime", Tag=3, Type=typing.Union[None, Nullable, uint]), ]) - locationID: 'uint' = 0 + areaID: 'uint' = 0 status: 'ServiceArea.Enums.OperationalStatusEnum' = 0 totalOperationalTime: 'typing.Union[None, Nullable, uint]' = None estimatedTime: 'typing.Union[None, Nullable, uint]' = None class Commands: @dataclass - class SelectLocations(ClusterCommand): + class SelectAreas(ClusterCommand): cluster_id: typing.ClassVar[int] = 0x00000150 command_id: typing.ClassVar[int] = 0x00000000 is_client: typing.ClassVar[bool] = True - response_type: typing.ClassVar[str] = 'SelectLocationsResponse' + response_type: typing.ClassVar[str] = 'SelectAreasResponse' @ChipUtility.classproperty def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="newLocations", Tag=0, Type=typing.Union[Nullable, typing.List[uint]]), + ClusterObjectFieldDescriptor(Label="newAreas", Tag=0, Type=typing.Union[Nullable, typing.List[uint]]), ]) - newLocations: 'typing.Union[Nullable, typing.List[uint]]' = NullValue + newAreas: 'typing.Union[Nullable, typing.List[uint]]' = NullValue @dataclass - class SelectLocationsResponse(ClusterCommand): + class SelectAreasResponse(ClusterCommand): cluster_id: typing.ClassVar[int] = 0x00000150 command_id: typing.ClassVar[int] = 0x00000001 is_client: typing.ClassVar[bool] = False @@ -31270,19 +31270,19 @@ class SelectLocationsResponse(ClusterCommand): def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="status", Tag=0, Type=ServiceArea.Enums.SelectLocationsStatus), + ClusterObjectFieldDescriptor(Label="status", Tag=0, Type=ServiceArea.Enums.SelectAreasStatus), ClusterObjectFieldDescriptor(Label="statusText", Tag=1, Type=typing.Optional[str]), ]) - status: 'ServiceArea.Enums.SelectLocationsStatus' = 0 + status: 'ServiceArea.Enums.SelectAreasStatus' = 0 statusText: 'typing.Optional[str]' = None @dataclass - class SkipCurrentLocation(ClusterCommand): + class SkipArea(ClusterCommand): cluster_id: typing.ClassVar[int] = 0x00000150 command_id: typing.ClassVar[int] = 0x00000002 is_client: typing.ClassVar[bool] = True - response_type: typing.ClassVar[str] = 'SkipCurrentLocationResponse' + response_type: typing.ClassVar[str] = 'SkipAreaResponse' @ChipUtility.classproperty def descriptor(cls) -> ClusterObjectDescriptor: @@ -31291,7 +31291,7 @@ def descriptor(cls) -> ClusterObjectDescriptor: ]) @dataclass - class SkipCurrentLocationResponse(ClusterCommand): + class SkipAreaResponse(ClusterCommand): cluster_id: typing.ClassVar[int] = 0x00000150 command_id: typing.ClassVar[int] = 0x00000003 is_client: typing.ClassVar[bool] = False @@ -31301,16 +31301,16 @@ class SkipCurrentLocationResponse(ClusterCommand): def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="status", Tag=0, Type=ServiceArea.Enums.SkipCurrentLocationStatus), + ClusterObjectFieldDescriptor(Label="status", Tag=0, Type=ServiceArea.Enums.SkipAreaStatus), ClusterObjectFieldDescriptor(Label="statusText", Tag=1, Type=typing.Optional[str]), ]) - status: 'ServiceArea.Enums.SkipCurrentLocationStatus' = 0 + status: 'ServiceArea.Enums.SkipAreaStatus' = 0 statusText: 'typing.Optional[str]' = None class Attributes: @dataclass - class SupportedLocations(ClusterAttributeDescriptor): + class SupportedAreas(ClusterAttributeDescriptor): @ChipUtility.classproperty def cluster_id(cls) -> int: return 0x00000150 @@ -31321,9 +31321,9 @@ def attribute_id(cls) -> int: @ChipUtility.classproperty def attribute_type(cls) -> ClusterObjectFieldDescriptor: - return ClusterObjectFieldDescriptor(Type=typing.List[ServiceArea.Structs.LocationStruct]) + return ClusterObjectFieldDescriptor(Type=typing.List[ServiceArea.Structs.AreaStruct]) - value: 'typing.List[ServiceArea.Structs.LocationStruct]' = field(default_factory=lambda: []) + value: 'typing.List[ServiceArea.Structs.AreaStruct]' = field(default_factory=lambda: []) @dataclass class SupportedMaps(ClusterAttributeDescriptor): @@ -31342,7 +31342,7 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: value: 'typing.Union[Nullable, typing.List[ServiceArea.Structs.MapStruct]]' = NullValue @dataclass - class SelectedLocations(ClusterAttributeDescriptor): + class SelectedAreas(ClusterAttributeDescriptor): @ChipUtility.classproperty def cluster_id(cls) -> int: return 0x00000150 @@ -31358,7 +31358,7 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: value: 'typing.Union[Nullable, typing.List[uint]]' = NullValue @dataclass - class CurrentLocation(ClusterAttributeDescriptor): + class CurrentArea(ClusterAttributeDescriptor): @ChipUtility.classproperty def cluster_id(cls) -> int: return 0x00000150 diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm index d0ea9a364af749..ce8cbd7a5621f0 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm @@ -3861,16 +3861,16 @@ static BOOL AttributeIsSpecifiedInServiceAreaCluster(AttributeId aAttributeId) { using namespace Clusters::ServiceArea; switch (aAttributeId) { - case Attributes::SupportedLocations::Id: { + case Attributes::SupportedAreas::Id: { return YES; } case Attributes::SupportedMaps::Id: { return YES; } - case Attributes::SelectedLocations::Id: { + case Attributes::SelectedAreas::Id: { return YES; } - case Attributes::CurrentLocation::Id: { + case Attributes::CurrentArea::Id: { return YES; } case Attributes::EstimatedEndTime::Id: { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm index 6e9fa8aa333a59..2a2cf4f84cb44d 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm @@ -11176,8 +11176,8 @@ static id _Nullable DecodeAttributeValueForServiceAreaCluster(AttributeId aAttri { using namespace Clusters::ServiceArea; switch (aAttributeId) { - case Attributes::SupportedLocations::Id: { - using TypeInfo = Attributes::SupportedLocations::TypeInfo; + case Attributes::SupportedAreas::Id: { + using TypeInfo = Attributes::SupportedAreas::TypeInfo; TypeInfo::DecodableType cppValue; *aError = DataModel::Decode(aReader, cppValue); if (*aError != CHIP_NO_ERROR) { @@ -11189,50 +11189,50 @@ static id _Nullable DecodeAttributeValueForServiceAreaCluster(AttributeId aAttri auto iter_0 = cppValue.begin(); while (iter_0.Next()) { auto & entry_0 = iter_0.GetValue(); - MTRServiceAreaClusterLocationStruct * newElement_0; - newElement_0 = [MTRServiceAreaClusterLocationStruct new]; - newElement_0.locationID = [NSNumber numberWithUnsignedInt:entry_0.locationID]; + MTRServiceAreaClusterAreaStruct * newElement_0; + newElement_0 = [MTRServiceAreaClusterAreaStruct new]; + newElement_0.areaID = [NSNumber numberWithUnsignedInt:entry_0.areaID]; if (entry_0.mapID.IsNull()) { newElement_0.mapID = nil; } else { newElement_0.mapID = [NSNumber numberWithUnsignedChar:entry_0.mapID.Value()]; } - newElement_0.locationInfo = [MTRServiceAreaClusterLocationInfoStruct new]; - if (entry_0.locationInfo.locationInfo.IsNull()) { - newElement_0.locationInfo.locationInfo = nil; + newElement_0.areaDesc = [MTRServiceAreaClusterAreaInfoStruct new]; + if (entry_0.areaDesc.locationInfo.IsNull()) { + newElement_0.areaDesc.locationInfo = nil; } else { - newElement_0.locationInfo.locationInfo = [MTRDataTypeLocationDescriptorStruct new]; - newElement_0.locationInfo.locationInfo.locationName = AsString(entry_0.locationInfo.locationInfo.Value().locationName); - if (newElement_0.locationInfo.locationInfo.locationName == nil) { + newElement_0.areaDesc.locationInfo = [MTRDataTypeLocationDescriptorStruct new]; + newElement_0.areaDesc.locationInfo.locationName = AsString(entry_0.areaDesc.locationInfo.Value().locationName); + if (newElement_0.areaDesc.locationInfo.locationName == nil) { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; *aError = err; return nil; } - if (entry_0.locationInfo.locationInfo.Value().floorNumber.IsNull()) { - newElement_0.locationInfo.locationInfo.floorNumber = nil; + if (entry_0.areaDesc.locationInfo.Value().floorNumber.IsNull()) { + newElement_0.areaDesc.locationInfo.floorNumber = nil; } else { - newElement_0.locationInfo.locationInfo.floorNumber = [NSNumber numberWithShort:entry_0.locationInfo.locationInfo.Value().floorNumber.Value()]; + newElement_0.areaDesc.locationInfo.floorNumber = [NSNumber numberWithShort:entry_0.areaDesc.locationInfo.Value().floorNumber.Value()]; } - if (entry_0.locationInfo.locationInfo.Value().areaType.IsNull()) { - newElement_0.locationInfo.locationInfo.areaType = nil; + if (entry_0.areaDesc.locationInfo.Value().areaType.IsNull()) { + newElement_0.areaDesc.locationInfo.areaType = nil; } else { - newElement_0.locationInfo.locationInfo.areaType = [NSNumber numberWithUnsignedChar:chip::to_underlying(entry_0.locationInfo.locationInfo.Value().areaType.Value())]; + newElement_0.areaDesc.locationInfo.areaType = [NSNumber numberWithUnsignedChar:chip::to_underlying(entry_0.areaDesc.locationInfo.Value().areaType.Value())]; } } - if (entry_0.locationInfo.landmarkTag.IsNull()) { - newElement_0.locationInfo.landmarkTag = nil; + if (entry_0.areaDesc.landmarkTag.IsNull()) { + newElement_0.areaDesc.landmarkTag = nil; } else { - newElement_0.locationInfo.landmarkTag = [NSNumber numberWithUnsignedChar:chip::to_underlying(entry_0.locationInfo.landmarkTag.Value())]; + newElement_0.areaDesc.landmarkTag = [NSNumber numberWithUnsignedChar:chip::to_underlying(entry_0.areaDesc.landmarkTag.Value())]; } - if (entry_0.locationInfo.positionTag.IsNull()) { - newElement_0.locationInfo.positionTag = nil; + if (entry_0.areaDesc.positionTag.IsNull()) { + newElement_0.areaDesc.positionTag = nil; } else { - newElement_0.locationInfo.positionTag = [NSNumber numberWithUnsignedChar:chip::to_underlying(entry_0.locationInfo.positionTag.Value())]; + newElement_0.areaDesc.positionTag = [NSNumber numberWithUnsignedChar:chip::to_underlying(entry_0.areaDesc.positionTag.Value())]; } - if (entry_0.locationInfo.surfaceTag.IsNull()) { - newElement_0.locationInfo.surfaceTag = nil; + if (entry_0.areaDesc.surfaceTag.IsNull()) { + newElement_0.areaDesc.surfaceTag = nil; } else { - newElement_0.locationInfo.surfaceTag = [NSNumber numberWithUnsignedChar:chip::to_underlying(entry_0.locationInfo.surfaceTag.Value())]; + newElement_0.areaDesc.surfaceTag = [NSNumber numberWithUnsignedChar:chip::to_underlying(entry_0.areaDesc.surfaceTag.Value())]; } [array_0 addObject:newElement_0]; } @@ -11282,8 +11282,8 @@ static id _Nullable DecodeAttributeValueForServiceAreaCluster(AttributeId aAttri } return value; } - case Attributes::SelectedLocations::Id: { - using TypeInfo = Attributes::SelectedLocations::TypeInfo; + case Attributes::SelectedAreas::Id: { + using TypeInfo = Attributes::SelectedAreas::TypeInfo; TypeInfo::DecodableType cppValue; *aError = DataModel::Decode(aReader, cppValue); if (*aError != CHIP_NO_ERROR) { @@ -11312,8 +11312,8 @@ static id _Nullable DecodeAttributeValueForServiceAreaCluster(AttributeId aAttri } return value; } - case Attributes::CurrentLocation::Id: { - using TypeInfo = Attributes::CurrentLocation::TypeInfo; + case Attributes::CurrentArea::Id: { + using TypeInfo = Attributes::CurrentArea::TypeInfo; TypeInfo::DecodableType cppValue; *aError = DataModel::Decode(aReader, cppValue); if (*aError != CHIP_NO_ERROR) { @@ -11360,7 +11360,7 @@ static id _Nullable DecodeAttributeValueForServiceAreaCluster(AttributeId aAttri auto & entry_1 = iter_1.GetValue(); MTRServiceAreaClusterProgressStruct * newElement_1; newElement_1 = [MTRServiceAreaClusterProgressStruct new]; - newElement_1.locationID = [NSNumber numberWithUnsignedInt:entry_1.locationID]; + newElement_1.areaID = [NSNumber numberWithUnsignedInt:entry_1.areaID]; newElement_1.status = [NSNumber numberWithUnsignedChar:chip::to_underlying(entry_1.status)]; if (entry_1.totalOperationalTime.HasValue()) { if (entry_1.totalOperationalTime.Value().IsNull()) { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index b151fcea89b3cc..fe78478449ad36 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -9696,25 +9696,25 @@ MTR_PROVISIONALLY_AVAILABLE @interface MTRBaseClusterServiceArea : MTRGenericBaseCluster /** - * Command SelectLocations + * Command SelectAreas * - * Command used to select a set of device locations, where the device is to operate + * Command used to select a set of device areas, where the device is to operate. */ -- (void)selectLocationsWithParams:(MTRServiceAreaClusterSelectLocationsParams *)params completion:(void (^)(MTRServiceAreaClusterSelectLocationsResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)selectAreasWithParams:(MTRServiceAreaClusterSelectAreasParams *)params completion:(void (^)(MTRServiceAreaClusterSelectAreasResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; /** - * Command SkipCurrentLocation + * Command SkipArea * - * This command is used to skip the current location where the device operates. + * This command is used to skip an area where the device operates. */ -- (void)skipCurrentLocationWithParams:(MTRServiceAreaClusterSkipCurrentLocationParams * _Nullable)params completion:(void (^)(MTRServiceAreaClusterSkipCurrentLocationResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)skipCurrentLocationWithCompletion:(void (^)(MTRServiceAreaClusterSkipCurrentLocationResponseParams * _Nullable data, NSError * _Nullable error))completion +- (void)skipAreaWithParams:(MTRServiceAreaClusterSkipAreaParams * _Nullable)params completion:(void (^)(MTRServiceAreaClusterSkipAreaResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)skipAreaWithCompletion:(void (^)(MTRServiceAreaClusterSkipAreaResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)readAttributeSupportedLocationsWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)subscribeAttributeSupportedLocationsWithParams:(MTRSubscribeParams *)params - subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; -+ (void)readAttributeSupportedLocationsWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)readAttributeSupportedAreasWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeSupportedAreasWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeSupportedAreasWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)readAttributeSupportedMapsWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)subscribeAttributeSupportedMapsWithParams:(MTRSubscribeParams *)params @@ -9722,17 +9722,17 @@ MTR_PROVISIONALLY_AVAILABLE reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; + (void)readAttributeSupportedMapsWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)readAttributeSelectedLocationsWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)subscribeAttributeSelectedLocationsWithParams:(MTRSubscribeParams *)params - subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; -+ (void)readAttributeSelectedLocationsWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)readAttributeSelectedAreasWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeSelectedAreasWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeSelectedAreasWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)readAttributeCurrentLocationWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)subscribeAttributeCurrentLocationWithParams:(MTRSubscribeParams *)params - subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; -+ (void)readAttributeCurrentLocationWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)readAttributeCurrentAreaWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)subscribeAttributeCurrentAreaWithParams:(MTRSubscribeParams *)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; ++ (void)readAttributeCurrentAreaWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)readAttributeEstimatedEndTimeWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)subscribeAttributeEstimatedEndTimeWithParams:(MTRSubscribeParams *)params @@ -19801,18 +19801,18 @@ typedef NS_ENUM(uint8_t, MTRServiceAreaOperationalStatus) { MTRServiceAreaOperationalStatusCompleted MTR_PROVISIONALLY_AVAILABLE = 0x03, } MTR_PROVISIONALLY_AVAILABLE; -typedef NS_ENUM(uint8_t, MTRServiceAreaSelectLocationsStatus) { - MTRServiceAreaSelectLocationsStatusSuccess MTR_PROVISIONALLY_AVAILABLE = 0x00, - MTRServiceAreaSelectLocationsStatusUnsupportedLocation MTR_PROVISIONALLY_AVAILABLE = 0x01, - MTRServiceAreaSelectLocationsStatusDuplicatedLocations MTR_PROVISIONALLY_AVAILABLE = 0x02, - MTRServiceAreaSelectLocationsStatusInvalidInMode MTR_PROVISIONALLY_AVAILABLE = 0x03, - MTRServiceAreaSelectLocationsStatusInvalidSet MTR_PROVISIONALLY_AVAILABLE = 0x04, +typedef NS_ENUM(uint8_t, MTRServiceAreaSelectAreasStatus) { + MTRServiceAreaSelectAreasStatusSuccess MTR_PROVISIONALLY_AVAILABLE = 0x00, + MTRServiceAreaSelectAreasStatusUnsupportedArea MTR_PROVISIONALLY_AVAILABLE = 0x01, + MTRServiceAreaSelectAreasStatusDuplicatedAreas MTR_PROVISIONALLY_AVAILABLE = 0x02, + MTRServiceAreaSelectAreasStatusInvalidInMode MTR_PROVISIONALLY_AVAILABLE = 0x03, + MTRServiceAreaSelectAreasStatusInvalidSet MTR_PROVISIONALLY_AVAILABLE = 0x04, } MTR_PROVISIONALLY_AVAILABLE; -typedef NS_ENUM(uint8_t, MTRServiceAreaSkipCurrentLocationStatus) { - MTRServiceAreaSkipCurrentLocationStatusSuccess MTR_PROVISIONALLY_AVAILABLE = 0x00, - MTRServiceAreaSkipCurrentLocationStatusInvalidLocationList MTR_PROVISIONALLY_AVAILABLE = 0x01, - MTRServiceAreaSkipCurrentLocationStatusInvalidInMode MTR_PROVISIONALLY_AVAILABLE = 0x02, +typedef NS_ENUM(uint8_t, MTRServiceAreaSkipAreaStatus) { + MTRServiceAreaSkipAreaStatusSuccess MTR_PROVISIONALLY_AVAILABLE = 0x00, + MTRServiceAreaSkipAreaStatusInvalidAreaList MTR_PROVISIONALLY_AVAILABLE = 0x01, + MTRServiceAreaSkipAreaStatusInvalidInMode MTR_PROVISIONALLY_AVAILABLE = 0x02, } MTR_PROVISIONALLY_AVAILABLE; typedef NS_OPTIONS(uint32_t, MTRServiceAreaFeature) { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm index 3ca3bfe55708dd..7a94c0954e1683 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm @@ -65364,10 +65364,10 @@ - (nullable instancetype)initWithDevice:(MTRBaseDevice *)device @implementation MTRBaseClusterServiceArea -- (void)selectLocationsWithParams:(MTRServiceAreaClusterSelectLocationsParams *)params completion:(void (^)(MTRServiceAreaClusterSelectLocationsResponseParams * _Nullable data, NSError * _Nullable error))completion +- (void)selectAreasWithParams:(MTRServiceAreaClusterSelectAreasParams *)params completion:(void (^)(MTRServiceAreaClusterSelectAreasResponseParams * _Nullable data, NSError * _Nullable error))completion { if (params == nil) { - params = [[MTRServiceAreaClusterSelectLocationsParams + params = [[MTRServiceAreaClusterSelectAreasParams alloc] init]; } @@ -65377,25 +65377,25 @@ - (void)selectLocationsWithParams:(MTRServiceAreaClusterSelectLocationsParams *) auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; - using RequestType = ServiceArea::Commands::SelectLocations::Type; + using RequestType = ServiceArea::Commands::SelectAreas::Type; [self.device _invokeKnownCommandWithEndpointID:self.endpointID clusterID:@(RequestType::GetClusterId()) commandID:@(RequestType::GetCommandId()) commandPayload:params timedInvokeTimeout:timedInvokeTimeoutMs serverSideProcessingTimeout:params.serverSideProcessingTimeout - responseClass:MTRServiceAreaClusterSelectLocationsResponseParams.class + responseClass:MTRServiceAreaClusterSelectAreasResponseParams.class queue:self.callbackQueue completion:responseHandler]; } -- (void)skipCurrentLocationWithCompletion:(void (^)(MTRServiceAreaClusterSkipCurrentLocationResponseParams * _Nullable data, NSError * _Nullable error))completion +- (void)skipAreaWithCompletion:(void (^)(MTRServiceAreaClusterSkipAreaResponseParams * _Nullable data, NSError * _Nullable error))completion { - [self skipCurrentLocationWithParams:nil completion:completion]; + [self skipAreaWithParams:nil completion:completion]; } -- (void)skipCurrentLocationWithParams:(MTRServiceAreaClusterSkipCurrentLocationParams * _Nullable)params completion:(void (^)(MTRServiceAreaClusterSkipCurrentLocationResponseParams * _Nullable data, NSError * _Nullable error))completion +- (void)skipAreaWithParams:(MTRServiceAreaClusterSkipAreaParams * _Nullable)params completion:(void (^)(MTRServiceAreaClusterSkipAreaResponseParams * _Nullable data, NSError * _Nullable error))completion { if (params == nil) { - params = [[MTRServiceAreaClusterSkipCurrentLocationParams + params = [[MTRServiceAreaClusterSkipAreaParams alloc] init]; } @@ -65405,21 +65405,21 @@ - (void)skipCurrentLocationWithParams:(MTRServiceAreaClusterSkipCurrentLocationP auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; - using RequestType = ServiceArea::Commands::SkipCurrentLocation::Type; + using RequestType = ServiceArea::Commands::SkipArea::Type; [self.device _invokeKnownCommandWithEndpointID:self.endpointID clusterID:@(RequestType::GetClusterId()) commandID:@(RequestType::GetCommandId()) commandPayload:params timedInvokeTimeout:timedInvokeTimeoutMs serverSideProcessingTimeout:params.serverSideProcessingTimeout - responseClass:MTRServiceAreaClusterSkipCurrentLocationResponseParams.class + responseClass:MTRServiceAreaClusterSkipAreaResponseParams.class queue:self.callbackQueue completion:responseHandler]; } -- (void)readAttributeSupportedLocationsWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +- (void)readAttributeSupportedAreasWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = ServiceArea::Attributes::SupportedLocations::TypeInfo; + using TypeInfo = ServiceArea::Attributes::SupportedAreas::TypeInfo; [self.device _readKnownAttributeWithEndpointID:self.endpointID clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -65428,11 +65428,11 @@ - (void)readAttributeSupportedLocationsWithCompletion:(void (^)(NSArray * _Nulla completion:completion]; } -- (void)subscribeAttributeSupportedLocationsWithParams:(MTRSubscribeParams * _Nonnull)params - subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +- (void)subscribeAttributeSupportedAreasWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler { - using TypeInfo = ServiceArea::Attributes::SupportedLocations::TypeInfo; + using TypeInfo = ServiceArea::Attributes::SupportedAreas::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -65442,9 +65442,9 @@ - (void)subscribeAttributeSupportedLocationsWithParams:(MTRSubscribeParams * _No subscriptionEstablished:subscriptionEstablished]; } -+ (void)readAttributeSupportedLocationsWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion ++ (void)readAttributeSupportedAreasWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = ServiceArea::Attributes::SupportedLocations::TypeInfo; + using TypeInfo = ServiceArea::Attributes::SupportedAreas::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() @@ -65489,9 +65489,9 @@ + (void)readAttributeSupportedMapsWithClusterStateCache:(MTRClusterStateCacheCon completion:completion]; } -- (void)readAttributeSelectedLocationsWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion +- (void)readAttributeSelectedAreasWithCompletion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = ServiceArea::Attributes::SelectedLocations::TypeInfo; + using TypeInfo = ServiceArea::Attributes::SelectedAreas::TypeInfo; [self.device _readKnownAttributeWithEndpointID:self.endpointID clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -65500,11 +65500,11 @@ - (void)readAttributeSelectedLocationsWithCompletion:(void (^)(NSArray * _Nullab completion:completion]; } -- (void)subscribeAttributeSelectedLocationsWithParams:(MTRSubscribeParams * _Nonnull)params - subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler +- (void)subscribeAttributeSelectedAreasWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler { - using TypeInfo = ServiceArea::Attributes::SelectedLocations::TypeInfo; + using TypeInfo = ServiceArea::Attributes::SelectedAreas::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -65514,9 +65514,9 @@ - (void)subscribeAttributeSelectedLocationsWithParams:(MTRSubscribeParams * _Non subscriptionEstablished:subscriptionEstablished]; } -+ (void)readAttributeSelectedLocationsWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion ++ (void)readAttributeSelectedAreasWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = ServiceArea::Attributes::SelectedLocations::TypeInfo; + using TypeInfo = ServiceArea::Attributes::SelectedAreas::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() @@ -65525,9 +65525,9 @@ + (void)readAttributeSelectedLocationsWithClusterStateCache:(MTRClusterStateCach completion:completion]; } -- (void)readAttributeCurrentLocationWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion +- (void)readAttributeCurrentAreaWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = ServiceArea::Attributes::CurrentLocation::TypeInfo; + using TypeInfo = ServiceArea::Attributes::CurrentArea::TypeInfo; [self.device _readKnownAttributeWithEndpointID:self.endpointID clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -65536,11 +65536,11 @@ - (void)readAttributeCurrentLocationWithCompletion:(void (^)(NSNumber * _Nullabl completion:completion]; } -- (void)subscribeAttributeCurrentLocationWithParams:(MTRSubscribeParams * _Nonnull)params - subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler +- (void)subscribeAttributeCurrentAreaWithParams:(MTRSubscribeParams * _Nonnull)params + subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished + reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler { - using TypeInfo = ServiceArea::Attributes::CurrentLocation::TypeInfo; + using TypeInfo = ServiceArea::Attributes::CurrentArea::TypeInfo; [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID clusterID:@(TypeInfo::GetClusterId()) attributeID:@(TypeInfo::GetAttributeId()) @@ -65550,9 +65550,9 @@ - (void)subscribeAttributeCurrentLocationWithParams:(MTRSubscribeParams * _Nonnu subscriptionEstablished:subscriptionEstablished]; } -+ (void)readAttributeCurrentLocationWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion ++ (void)readAttributeCurrentAreaWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { - using TypeInfo = ServiceArea::Attributes::CurrentLocation::TypeInfo; + using TypeInfo = ServiceArea::Attributes::CurrentArea::TypeInfo; [clusterStateCacheContainer _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) clusterID:TypeInfo::GetClusterId() diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h index f920a8e336cd92..36ba74c1b9867a 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h @@ -3139,10 +3139,10 @@ typedef NS_ENUM(uint32_t, MTRAttributeIDType) { MTRAttributeIDTypeClusterBarrierControlAttributeClusterRevisionID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = MTRAttributeIDTypeGlobalAttributeClusterRevisionID, // Cluster ServiceArea attributes - MTRAttributeIDTypeClusterServiceAreaAttributeSupportedLocationsID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + MTRAttributeIDTypeClusterServiceAreaAttributeSupportedAreasID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, MTRAttributeIDTypeClusterServiceAreaAttributeSupportedMapsID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, - MTRAttributeIDTypeClusterServiceAreaAttributeSelectedLocationsID MTR_PROVISIONALLY_AVAILABLE = 0x00000002, - MTRAttributeIDTypeClusterServiceAreaAttributeCurrentLocationID MTR_PROVISIONALLY_AVAILABLE = 0x00000003, + MTRAttributeIDTypeClusterServiceAreaAttributeSelectedAreasID MTR_PROVISIONALLY_AVAILABLE = 0x00000002, + MTRAttributeIDTypeClusterServiceAreaAttributeCurrentAreaID MTR_PROVISIONALLY_AVAILABLE = 0x00000003, MTRAttributeIDTypeClusterServiceAreaAttributeEstimatedEndTimeID MTR_PROVISIONALLY_AVAILABLE = 0x00000004, MTRAttributeIDTypeClusterServiceAreaAttributeProgressID MTR_PROVISIONALLY_AVAILABLE = 0x00000005, MTRAttributeIDTypeClusterServiceAreaAttributeGeneratedCommandListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeGeneratedCommandListID, @@ -6595,10 +6595,10 @@ typedef NS_ENUM(uint32_t, MTRCommandIDType) { MTRCommandIDTypeClusterBarrierControlCommandBarrierControlStopID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000001, // Cluster ServiceArea commands - MTRCommandIDTypeClusterServiceAreaCommandSelectLocationsID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, - MTRCommandIDTypeClusterServiceAreaCommandSelectLocationsResponseID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, - MTRCommandIDTypeClusterServiceAreaCommandSkipCurrentLocationID MTR_PROVISIONALLY_AVAILABLE = 0x00000002, - MTRCommandIDTypeClusterServiceAreaCommandSkipCurrentLocationResponseID MTR_PROVISIONALLY_AVAILABLE = 0x00000003, + MTRCommandIDTypeClusterServiceAreaCommandSelectAreasID MTR_PROVISIONALLY_AVAILABLE = 0x00000000, + MTRCommandIDTypeClusterServiceAreaCommandSelectAreasResponseID MTR_PROVISIONALLY_AVAILABLE = 0x00000001, + MTRCommandIDTypeClusterServiceAreaCommandSkipAreaID MTR_PROVISIONALLY_AVAILABLE = 0x00000002, + MTRCommandIDTypeClusterServiceAreaCommandSkipAreaResponseID MTR_PROVISIONALLY_AVAILABLE = 0x00000003, // Cluster Thermostat deprecated command id names MTRClusterThermostatCommandSetpointRaiseLowerID diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm index 6191e7c60d53eb..d7c40ca085b628 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm @@ -5450,20 +5450,20 @@ switch (attributeID) { // Cluster ServiceArea attributes - case MTRAttributeIDTypeClusterServiceAreaAttributeSupportedLocationsID: - result = @"SupportedLocations"; + case MTRAttributeIDTypeClusterServiceAreaAttributeSupportedAreasID: + result = @"SupportedAreas"; break; case MTRAttributeIDTypeClusterServiceAreaAttributeSupportedMapsID: result = @"SupportedMaps"; break; - case MTRAttributeIDTypeClusterServiceAreaAttributeSelectedLocationsID: - result = @"SelectedLocations"; + case MTRAttributeIDTypeClusterServiceAreaAttributeSelectedAreasID: + result = @"SelectedAreas"; break; - case MTRAttributeIDTypeClusterServiceAreaAttributeCurrentLocationID: - result = @"CurrentLocation"; + case MTRAttributeIDTypeClusterServiceAreaAttributeCurrentAreaID: + result = @"CurrentArea"; break; case MTRAttributeIDTypeClusterServiceAreaAttributeEstimatedEndTimeID: diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h index 44ecc1e0119c46..373a873d859389 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h @@ -4510,18 +4510,18 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) MTR_PROVISIONALLY_AVAILABLE @interface MTRClusterServiceArea : MTRGenericCluster -- (void)selectLocationsWithParams:(MTRServiceAreaClusterSelectLocationsParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRServiceAreaClusterSelectLocationsResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)skipCurrentLocationWithParams:(MTRServiceAreaClusterSkipCurrentLocationParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRServiceAreaClusterSkipCurrentLocationResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)skipCurrentLocationWithExpectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRServiceAreaClusterSkipCurrentLocationResponseParams * _Nullable data, NSError * _Nullable error))completion +- (void)selectAreasWithParams:(MTRServiceAreaClusterSelectAreasParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRServiceAreaClusterSelectAreasResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)skipAreaWithParams:(MTRServiceAreaClusterSkipAreaParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRServiceAreaClusterSkipAreaResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; +- (void)skipAreaWithExpectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRServiceAreaClusterSkipAreaResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (NSDictionary * _Nullable)readAttributeSupportedLocationsWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; +- (NSDictionary * _Nullable)readAttributeSupportedAreasWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; - (NSDictionary * _Nullable)readAttributeSupportedMapsWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; -- (NSDictionary * _Nullable)readAttributeSelectedLocationsWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; +- (NSDictionary * _Nullable)readAttributeSelectedAreasWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; -- (NSDictionary * _Nullable)readAttributeCurrentLocationWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; +- (NSDictionary * _Nullable)readAttributeCurrentAreaWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; - (NSDictionary * _Nullable)readAttributeEstimatedEndTimeWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm index 8e06c4d288084f..d0944234c6fbed 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm @@ -12837,10 +12837,10 @@ - (void)barrierControlStopWithExpectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRServiceAreaClusterSelectLocationsResponseParams * _Nullable data, NSError * _Nullable error))completion +- (void)selectAreasWithParams:(MTRServiceAreaClusterSelectAreasParams *)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRServiceAreaClusterSelectAreasResponseParams * _Nullable data, NSError * _Nullable error))completion { if (params == nil) { - params = [[MTRServiceAreaClusterSelectLocationsParams + params = [[MTRServiceAreaClusterSelectAreasParams alloc] init]; } @@ -12850,7 +12850,7 @@ - (void)selectLocationsWithParams:(MTRServiceAreaClusterSelectLocationsParams *) auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; - using RequestType = ServiceArea::Commands::SelectLocations::Type; + using RequestType = ServiceArea::Commands::SelectAreas::Type; [self.device _invokeKnownCommandWithEndpointID:self.endpointID clusterID:@(RequestType::GetClusterId()) commandID:@(RequestType::GetCommandId()) @@ -12859,19 +12859,19 @@ - (void)selectLocationsWithParams:(MTRServiceAreaClusterSelectLocationsParams *) expectedValueInterval:expectedValueIntervalMs timedInvokeTimeout:timedInvokeTimeoutMs serverSideProcessingTimeout:params.serverSideProcessingTimeout - responseClass:MTRServiceAreaClusterSelectLocationsResponseParams.class + responseClass:MTRServiceAreaClusterSelectAreasResponseParams.class queue:self.callbackQueue completion:responseHandler]; } -- (void)skipCurrentLocationWithExpectedValues:(NSArray *> *)expectedValues expectedValueInterval:(NSNumber *)expectedValueIntervalMs completion:(void (^)(MTRServiceAreaClusterSkipCurrentLocationResponseParams * _Nullable data, NSError * _Nullable error))completion +- (void)skipAreaWithExpectedValues:(NSArray *> *)expectedValues expectedValueInterval:(NSNumber *)expectedValueIntervalMs completion:(void (^)(MTRServiceAreaClusterSkipAreaResponseParams * _Nullable data, NSError * _Nullable error))completion { - [self skipCurrentLocationWithParams:nil expectedValues:expectedValues expectedValueInterval:expectedValueIntervalMs completion:completion]; + [self skipAreaWithParams:nil expectedValues:expectedValues expectedValueInterval:expectedValueIntervalMs completion:completion]; } -- (void)skipCurrentLocationWithParams:(MTRServiceAreaClusterSkipCurrentLocationParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRServiceAreaClusterSkipCurrentLocationResponseParams * _Nullable data, NSError * _Nullable error))completion +- (void)skipAreaWithParams:(MTRServiceAreaClusterSkipAreaParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRServiceAreaClusterSkipAreaResponseParams * _Nullable data, NSError * _Nullable error))completion { if (params == nil) { - params = [[MTRServiceAreaClusterSkipCurrentLocationParams + params = [[MTRServiceAreaClusterSkipAreaParams alloc] init]; } @@ -12881,7 +12881,7 @@ - (void)skipCurrentLocationWithParams:(MTRServiceAreaClusterSkipCurrentLocationP auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; - using RequestType = ServiceArea::Commands::SkipCurrentLocation::Type; + using RequestType = ServiceArea::Commands::SkipArea::Type; [self.device _invokeKnownCommandWithEndpointID:self.endpointID clusterID:@(RequestType::GetClusterId()) commandID:@(RequestType::GetCommandId()) @@ -12890,14 +12890,14 @@ - (void)skipCurrentLocationWithParams:(MTRServiceAreaClusterSkipCurrentLocationP expectedValueInterval:expectedValueIntervalMs timedInvokeTimeout:timedInvokeTimeoutMs serverSideProcessingTimeout:params.serverSideProcessingTimeout - responseClass:MTRServiceAreaClusterSkipCurrentLocationResponseParams.class + responseClass:MTRServiceAreaClusterSkipAreaResponseParams.class queue:self.callbackQueue completion:responseHandler]; } -- (NSDictionary * _Nullable)readAttributeSupportedLocationsWithParams:(MTRReadParams * _Nullable)params +- (NSDictionary * _Nullable)readAttributeSupportedAreasWithParams:(MTRReadParams * _Nullable)params { - return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeServiceAreaID) attributeID:@(MTRAttributeIDTypeClusterServiceAreaAttributeSupportedLocationsID) params:params]; + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeServiceAreaID) attributeID:@(MTRAttributeIDTypeClusterServiceAreaAttributeSupportedAreasID) params:params]; } - (NSDictionary * _Nullable)readAttributeSupportedMapsWithParams:(MTRReadParams * _Nullable)params @@ -12905,14 +12905,14 @@ - (void)skipCurrentLocationWithParams:(MTRServiceAreaClusterSkipCurrentLocationP return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeServiceAreaID) attributeID:@(MTRAttributeIDTypeClusterServiceAreaAttributeSupportedMapsID) params:params]; } -- (NSDictionary * _Nullable)readAttributeSelectedLocationsWithParams:(MTRReadParams * _Nullable)params +- (NSDictionary * _Nullable)readAttributeSelectedAreasWithParams:(MTRReadParams * _Nullable)params { - return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeServiceAreaID) attributeID:@(MTRAttributeIDTypeClusterServiceAreaAttributeSelectedLocationsID) params:params]; + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeServiceAreaID) attributeID:@(MTRAttributeIDTypeClusterServiceAreaAttributeSelectedAreasID) params:params]; } -- (NSDictionary * _Nullable)readAttributeCurrentLocationWithParams:(MTRReadParams * _Nullable)params +- (NSDictionary * _Nullable)readAttributeCurrentAreaWithParams:(MTRReadParams * _Nullable)params { - return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeServiceAreaID) attributeID:@(MTRAttributeIDTypeClusterServiceAreaAttributeCurrentLocationID) params:params]; + return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeServiceAreaID) attributeID:@(MTRAttributeIDTypeClusterServiceAreaAttributeCurrentAreaID) params:params]; } - (NSDictionary * _Nullable)readAttributeEstimatedEndTimeWithParams:(MTRReadParams * _Nullable)params diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index 62f200fe8623f7..a1255fd62f2d23 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -7637,9 +7637,9 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @end MTR_PROVISIONALLY_AVAILABLE -@interface MTRServiceAreaClusterSelectLocationsParams : NSObject +@interface MTRServiceAreaClusterSelectAreasParams : NSObject -@property (nonatomic, copy, getter=getNewLocations) NSArray * _Nullable newLocations MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy, getter=getNewAreas) NSArray * _Nullable newAreas MTR_PROVISIONALLY_AVAILABLE; /** * Controls whether the command is a timed command (using Timed Invoke). * @@ -7667,14 +7667,14 @@ MTR_PROVISIONALLY_AVAILABLE @end MTR_PROVISIONALLY_AVAILABLE -@interface MTRServiceAreaClusterSelectLocationsResponseParams : NSObject +@interface MTRServiceAreaClusterSelectAreasResponseParams : NSObject @property (nonatomic, copy) NSNumber * _Nonnull status MTR_PROVISIONALLY_AVAILABLE; @property (nonatomic, copy) NSString * _Nullable statusText MTR_PROVISIONALLY_AVAILABLE; /** - * Initialize an MTRServiceAreaClusterSelectLocationsResponseParams with a response-value dictionary + * Initialize an MTRServiceAreaClusterSelectAreasResponseParams with a response-value dictionary * of the sort that MTRDeviceResponseHandler would receive. * * Will return nil and hand out an error if the response-value dictionary is not @@ -7688,7 +7688,7 @@ MTR_PROVISIONALLY_AVAILABLE @end MTR_PROVISIONALLY_AVAILABLE -@interface MTRServiceAreaClusterSkipCurrentLocationParams : NSObject +@interface MTRServiceAreaClusterSkipAreaParams : NSObject /** * Controls whether the command is a timed command (using Timed Invoke). * @@ -7716,14 +7716,14 @@ MTR_PROVISIONALLY_AVAILABLE @end MTR_PROVISIONALLY_AVAILABLE -@interface MTRServiceAreaClusterSkipCurrentLocationResponseParams : NSObject +@interface MTRServiceAreaClusterSkipAreaResponseParams : NSObject @property (nonatomic, copy) NSNumber * _Nonnull status MTR_PROVISIONALLY_AVAILABLE; @property (nonatomic, copy) NSString * _Nullable statusText MTR_PROVISIONALLY_AVAILABLE; /** - * Initialize an MTRServiceAreaClusterSkipCurrentLocationResponseParams with a response-value dictionary + * Initialize an MTRServiceAreaClusterSkipAreaResponseParams with a response-value dictionary * of the sort that MTRDeviceResponseHandler would receive. * * Will return nil and hand out an error if the response-value dictionary is not diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index 6b10028ec18d78..efeaaa5aa5f50f 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -21784,12 +21784,12 @@ - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader } @end -@implementation MTRServiceAreaClusterSelectLocationsParams +@implementation MTRServiceAreaClusterSelectAreasParams - (instancetype)init { if (self = [super init]) { - _newLocations = nil; + _newAreas = nil; _timedInvokeTimeoutMs = nil; _serverSideProcessingTimeout = nil; } @@ -21798,9 +21798,9 @@ - (instancetype)init - (id)copyWithZone:(NSZone * _Nullable)zone; { - auto other = [[MTRServiceAreaClusterSelectLocationsParams alloc] init]; + auto other = [[MTRServiceAreaClusterSelectAreasParams alloc] init]; - other.newLocations = self.newLocations; + other.newAreas = self.newAreas; other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; other.serverSideProcessingTimeout = self.serverSideProcessingTimeout; @@ -21809,41 +21809,41 @@ - (id)copyWithZone:(NSZone * _Nullable)zone; - (NSString *)description { - NSString * descriptionString = [NSString stringWithFormat:@"<%@: newLocations:%@; >", NSStringFromClass([self class]), _newLocations]; + NSString * descriptionString = [NSString stringWithFormat:@"<%@: newAreas:%@; >", NSStringFromClass([self class]), _newAreas]; return descriptionString; } @end -@implementation MTRServiceAreaClusterSelectLocationsParams (InternalMethods) +@implementation MTRServiceAreaClusterSelectAreasParams (InternalMethods) - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader { - chip::app::Clusters::ServiceArea::Commands::SelectLocations::Type encodableStruct; + chip::app::Clusters::ServiceArea::Commands::SelectAreas::Type encodableStruct; ListFreer listFreer; { - if (self.newLocations == nil) { - encodableStruct.newLocations.SetNull(); + if (self.newAreas == nil) { + encodableStruct.newAreas.SetNull(); } else { - auto & nonNullValue_0 = encodableStruct.newLocations.SetNonNull(); + auto & nonNullValue_0 = encodableStruct.newAreas.SetNonNull(); { using ListType_1 = std::remove_reference_t; using ListMemberType_1 = ListMemberTypeGetter::Type; - if (self.newLocations.count != 0) { - auto * listHolder_1 = new ListHolder(self.newLocations.count); + if (self.newAreas.count != 0) { + auto * listHolder_1 = new ListHolder(self.newAreas.count); if (listHolder_1 == nullptr || listHolder_1->mList == nullptr) { return CHIP_ERROR_INVALID_ARGUMENT; } listFreer.add(listHolder_1); - for (size_t i_1 = 0; i_1 < self.newLocations.count; ++i_1) { - if (![self.newLocations[i_1] isKindOfClass:[NSNumber class]]) { + for (size_t i_1 = 0; i_1 < self.newAreas.count; ++i_1) { + if (![self.newAreas[i_1] isKindOfClass:[NSNumber class]]) { // Wrong kind of value. return CHIP_ERROR_INVALID_ARGUMENT; } - auto element_1 = (NSNumber *) self.newLocations[i_1]; + auto element_1 = (NSNumber *) self.newAreas[i_1]; listHolder_1->mList[i_1] = element_1.unsignedIntValue; } - nonNullValue_0 = ListType_1(listHolder_1->mList, self.newLocations.count); + nonNullValue_0 = ListType_1(listHolder_1->mList, self.newAreas.count); } else { nonNullValue_0 = ListType_1(); } @@ -21889,7 +21889,7 @@ - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader } @end -@implementation MTRServiceAreaClusterSelectLocationsResponseParams +@implementation MTRServiceAreaClusterSelectAreasResponseParams - (instancetype)init { if (self = [super init]) { @@ -21903,7 +21903,7 @@ - (instancetype)init - (id)copyWithZone:(NSZone * _Nullable)zone; { - auto other = [[MTRServiceAreaClusterSelectLocationsResponseParams alloc] init]; + auto other = [[MTRServiceAreaClusterSelectAreasResponseParams alloc] init]; other.status = self.status; other.statusText = self.statusText; @@ -21924,7 +21924,7 @@ - (nullable instancetype)initWithResponseValue:(NSDictionary *)r return nil; } - using DecodableType = chip::app::Clusters::ServiceArea::Commands::SelectLocationsResponse::DecodableType; + using DecodableType = chip::app::Clusters::ServiceArea::Commands::SelectAreasResponse::DecodableType; chip::System::PacketBufferHandle buffer = [MTRBaseDevice _responseDataForCommand:responseValue clusterID:DecodableType::GetClusterId() commandID:DecodableType::GetCommandId() @@ -21959,9 +21959,9 @@ - (nullable instancetype)initWithResponseValue:(NSDictionary *)r @end -@implementation MTRServiceAreaClusterSelectLocationsResponseParams (InternalMethods) +@implementation MTRServiceAreaClusterSelectAreasResponseParams (InternalMethods) -- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::ServiceArea::Commands::SelectLocationsResponse::DecodableType &)decodableStruct +- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::ServiceArea::Commands::SelectAreasResponse::DecodableType &)decodableStruct { { self.status = [NSNumber numberWithUnsignedChar:chip::to_underlying(decodableStruct.status)]; @@ -21982,7 +21982,7 @@ - (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::ServiceA @end -@implementation MTRServiceAreaClusterSkipCurrentLocationParams +@implementation MTRServiceAreaClusterSkipAreaParams - (instancetype)init { if (self = [super init]) { @@ -21994,7 +21994,7 @@ - (instancetype)init - (id)copyWithZone:(NSZone * _Nullable)zone; { - auto other = [[MTRServiceAreaClusterSkipCurrentLocationParams alloc] init]; + auto other = [[MTRServiceAreaClusterSkipAreaParams alloc] init]; other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; other.serverSideProcessingTimeout = self.serverSideProcessingTimeout; @@ -22010,11 +22010,11 @@ - (NSString *)description @end -@implementation MTRServiceAreaClusterSkipCurrentLocationParams (InternalMethods) +@implementation MTRServiceAreaClusterSkipAreaParams (InternalMethods) - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader { - chip::app::Clusters::ServiceArea::Commands::SkipCurrentLocation::Type encodableStruct; + chip::app::Clusters::ServiceArea::Commands::SkipArea::Type encodableStruct; ListFreer listFreer; auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0); @@ -22055,7 +22055,7 @@ - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader } @end -@implementation MTRServiceAreaClusterSkipCurrentLocationResponseParams +@implementation MTRServiceAreaClusterSkipAreaResponseParams - (instancetype)init { if (self = [super init]) { @@ -22069,7 +22069,7 @@ - (instancetype)init - (id)copyWithZone:(NSZone * _Nullable)zone; { - auto other = [[MTRServiceAreaClusterSkipCurrentLocationResponseParams alloc] init]; + auto other = [[MTRServiceAreaClusterSkipAreaResponseParams alloc] init]; other.status = self.status; other.statusText = self.statusText; @@ -22090,7 +22090,7 @@ - (nullable instancetype)initWithResponseValue:(NSDictionary *)r return nil; } - using DecodableType = chip::app::Clusters::ServiceArea::Commands::SkipCurrentLocationResponse::DecodableType; + using DecodableType = chip::app::Clusters::ServiceArea::Commands::SkipAreaResponse::DecodableType; chip::System::PacketBufferHandle buffer = [MTRBaseDevice _responseDataForCommand:responseValue clusterID:DecodableType::GetClusterId() commandID:DecodableType::GetCommandId() @@ -22125,9 +22125,9 @@ - (nullable instancetype)initWithResponseValue:(NSDictionary *)r @end -@implementation MTRServiceAreaClusterSkipCurrentLocationResponseParams (InternalMethods) +@implementation MTRServiceAreaClusterSkipAreaResponseParams (InternalMethods) -- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::ServiceArea::Commands::SkipCurrentLocationResponse::DecodableType &)decodableStruct +- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::ServiceArea::Commands::SkipAreaResponse::DecodableType &)decodableStruct { { self.status = [NSNumber numberWithUnsignedChar:chip::to_underlying(decodableStruct.status)]; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h index 93191eb3caa64d..4504aefdfc4e91 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h @@ -1432,27 +1432,27 @@ NS_ASSUME_NONNULL_BEGIN @end -@interface MTRServiceAreaClusterSelectLocationsParams (InternalMethods) +@interface MTRServiceAreaClusterSelectAreasParams (InternalMethods) - (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; @end -@interface MTRServiceAreaClusterSelectLocationsResponseParams (InternalMethods) +@interface MTRServiceAreaClusterSelectAreasResponseParams (InternalMethods) -- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::ServiceArea::Commands::SelectLocationsResponse::DecodableType &)decodableStruct; +- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::ServiceArea::Commands::SelectAreasResponse::DecodableType &)decodableStruct; @end -@interface MTRServiceAreaClusterSkipCurrentLocationParams (InternalMethods) +@interface MTRServiceAreaClusterSkipAreaParams (InternalMethods) - (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; @end -@interface MTRServiceAreaClusterSkipCurrentLocationResponseParams (InternalMethods) +@interface MTRServiceAreaClusterSkipAreaResponseParams (InternalMethods) -- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::ServiceArea::Commands::SkipCurrentLocationResponse::DecodableType &)decodableStruct; +- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::ServiceArea::Commands::SkipAreaResponse::DecodableType &)decodableStruct; @end diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h index 6535195be109c9..27d774ef5cc31d 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h @@ -1588,7 +1588,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @end MTR_PROVISIONALLY_AVAILABLE -@interface MTRServiceAreaClusterLocationInfoStruct : NSObject +@interface MTRServiceAreaClusterAreaInfoStruct : NSObject @property (nonatomic, copy) MTRDataTypeLocationDescriptorStruct * _Nullable locationInfo MTR_PROVISIONALLY_AVAILABLE; @property (nonatomic, copy) NSNumber * _Nullable landmarkTag MTR_PROVISIONALLY_AVAILABLE; @property (nonatomic, copy) NSNumber * _Nullable positionTag MTR_PROVISIONALLY_AVAILABLE; @@ -1596,10 +1596,10 @@ MTR_PROVISIONALLY_AVAILABLE @end MTR_PROVISIONALLY_AVAILABLE -@interface MTRServiceAreaClusterLocationStruct : NSObject -@property (nonatomic, copy) NSNumber * _Nonnull locationID MTR_PROVISIONALLY_AVAILABLE; +@interface MTRServiceAreaClusterAreaStruct : NSObject +@property (nonatomic, copy) NSNumber * _Nonnull areaID MTR_PROVISIONALLY_AVAILABLE; @property (nonatomic, copy) NSNumber * _Nullable mapID MTR_PROVISIONALLY_AVAILABLE; -@property (nonatomic, copy) MTRServiceAreaClusterLocationInfoStruct * _Nonnull locationInfo MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) MTRServiceAreaClusterAreaInfoStruct * _Nonnull areaDesc MTR_PROVISIONALLY_AVAILABLE; @end MTR_PROVISIONALLY_AVAILABLE @@ -1610,7 +1610,7 @@ MTR_PROVISIONALLY_AVAILABLE MTR_PROVISIONALLY_AVAILABLE @interface MTRServiceAreaClusterProgressStruct : NSObject -@property (nonatomic, copy) NSNumber * _Nonnull locationID MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull areaID MTR_PROVISIONALLY_AVAILABLE; @property (nonatomic, copy) NSNumber * _Nonnull status MTR_PROVISIONALLY_AVAILABLE; @property (nonatomic, copy) NSNumber * _Nullable totalOperationalTime MTR_PROVISIONALLY_AVAILABLE; @property (nonatomic, copy) NSNumber * _Nullable estimatedTime MTR_PROVISIONALLY_AVAILABLE; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm index 6cafc8a4b50270..5821b104376d5a 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm @@ -6610,7 +6610,7 @@ - (NSString *)description @end -@implementation MTRServiceAreaClusterLocationInfoStruct +@implementation MTRServiceAreaClusterAreaInfoStruct - (instancetype)init { if (self = [super init]) { @@ -6628,7 +6628,7 @@ - (instancetype)init - (id)copyWithZone:(NSZone * _Nullable)zone { - auto other = [[MTRServiceAreaClusterLocationInfoStruct alloc] init]; + auto other = [[MTRServiceAreaClusterAreaInfoStruct alloc] init]; other.locationInfo = self.locationInfo; other.landmarkTag = self.landmarkTag; @@ -6646,34 +6646,34 @@ - (NSString *)description @end -@implementation MTRServiceAreaClusterLocationStruct +@implementation MTRServiceAreaClusterAreaStruct - (instancetype)init { if (self = [super init]) { - _locationID = @(0); + _areaID = @(0); _mapID = nil; - _locationInfo = [MTRServiceAreaClusterLocationInfoStruct new]; + _areaDesc = [MTRServiceAreaClusterAreaInfoStruct new]; } return self; } - (id)copyWithZone:(NSZone * _Nullable)zone { - auto other = [[MTRServiceAreaClusterLocationStruct alloc] init]; + auto other = [[MTRServiceAreaClusterAreaStruct alloc] init]; - other.locationID = self.locationID; + other.areaID = self.areaID; other.mapID = self.mapID; - other.locationInfo = self.locationInfo; + other.areaDesc = self.areaDesc; return other; } - (NSString *)description { - NSString * descriptionString = [NSString stringWithFormat:@"<%@: locationID:%@; mapID:%@; locationInfo:%@; >", NSStringFromClass([self class]), _locationID, _mapID, _locationInfo]; + NSString * descriptionString = [NSString stringWithFormat:@"<%@: areaID:%@; mapID:%@; areaDesc:%@; >", NSStringFromClass([self class]), _areaID, _mapID, _areaDesc]; return descriptionString; } @@ -6714,7 +6714,7 @@ - (instancetype)init { if (self = [super init]) { - _locationID = @(0); + _areaID = @(0); _status = @(0); @@ -6729,7 +6729,7 @@ - (id)copyWithZone:(NSZone * _Nullable)zone { auto other = [[MTRServiceAreaClusterProgressStruct alloc] init]; - other.locationID = self.locationID; + other.areaID = self.areaID; other.status = self.status; other.totalOperationalTime = self.totalOperationalTime; other.estimatedTime = self.estimatedTime; @@ -6739,7 +6739,7 @@ - (id)copyWithZone:(NSZone * _Nullable)zone - (NSString *)description { - NSString * descriptionString = [NSString stringWithFormat:@"<%@: locationID:%@; status:%@; totalOperationalTime:%@; estimatedTime:%@; >", NSStringFromClass([self class]), _locationID, _status, _totalOperationalTime, _estimatedTime]; + NSString * descriptionString = [NSString stringWithFormat:@"<%@: areaID:%@; status:%@; totalOperationalTime:%@; estimatedTime:%@; >", NSStringFromClass([self class]), _areaID, _status, _totalOperationalTime, _estimatedTime]; return descriptionString; } diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h index 8a55a7680596c8..811352a6d38f7e 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h @@ -2566,14 +2566,14 @@ static auto __attribute__((unused)) EnsureKnownEnumValue(ServiceArea::Operationa return EnumType::kUnknownEnumValue; } } -static auto __attribute__((unused)) EnsureKnownEnumValue(ServiceArea::SelectLocationsStatus val) +static auto __attribute__((unused)) EnsureKnownEnumValue(ServiceArea::SelectAreasStatus val) { - using EnumType = ServiceArea::SelectLocationsStatus; + using EnumType = ServiceArea::SelectAreasStatus; switch (val) { case EnumType::kSuccess: - case EnumType::kUnsupportedLocation: - case EnumType::kDuplicatedLocations: + case EnumType::kUnsupportedArea: + case EnumType::kDuplicatedAreas: case EnumType::kInvalidInMode: case EnumType::kInvalidSet: return val; @@ -2581,13 +2581,13 @@ static auto __attribute__((unused)) EnsureKnownEnumValue(ServiceArea::SelectLoca return EnumType::kUnknownEnumValue; } } -static auto __attribute__((unused)) EnsureKnownEnumValue(ServiceArea::SkipCurrentLocationStatus val) +static auto __attribute__((unused)) EnsureKnownEnumValue(ServiceArea::SkipAreaStatus val) { - using EnumType = ServiceArea::SkipCurrentLocationStatus; + using EnumType = ServiceArea::SkipAreaStatus; switch (val) { case EnumType::kSuccess: - case EnumType::kInvalidLocationList: + case EnumType::kInvalidAreaList: case EnumType::kInvalidInMode: return val; default: diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h index e375b394871e69..3c8d52d0bed54d 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h @@ -3807,14 +3807,14 @@ enum class OperationalStatusEnum : uint8_t kUnknownEnumValue = 4, }; -// Enum for SelectLocationsStatus -enum class SelectLocationsStatus : uint8_t +// Enum for SelectAreasStatus +enum class SelectAreasStatus : uint8_t { - kSuccess = 0x00, - kUnsupportedLocation = 0x01, - kDuplicatedLocations = 0x02, - kInvalidInMode = 0x03, - kInvalidSet = 0x04, + kSuccess = 0x00, + kUnsupportedArea = 0x01, + kDuplicatedAreas = 0x02, + kInvalidInMode = 0x03, + kInvalidSet = 0x04, // All received enum values that are not listed above will be mapped // to kUnknownEnumValue. This is a helper enum value that should only // be used by code to process how it handles receiving and unknown @@ -3822,12 +3822,12 @@ enum class SelectLocationsStatus : uint8_t kUnknownEnumValue = 5, }; -// Enum for SkipCurrentLocationStatus -enum class SkipCurrentLocationStatus : uint8_t +// Enum for SkipAreaStatus +enum class SkipAreaStatus : uint8_t { - kSuccess = 0x00, - kInvalidLocationList = 0x01, - kInvalidInMode = 0x02, + kSuccess = 0x00, + kInvalidAreaList = 0x01, + kInvalidInMode = 0x02, // All received enum values that are not listed above will be mapped // to kUnknownEnumValue. This is a helper enum value that should only // be used by code to process how it handles receiving and unknown diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp index b725407b284118..916d5ed27457ab 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp @@ -20316,7 +20316,7 @@ namespace Events {} // namespace Events namespace ServiceArea { namespace Structs { -namespace LocationInfoStruct { +namespace AreaInfoStruct { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; @@ -20365,15 +20365,15 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) } } -} // namespace LocationInfoStruct +} // namespace AreaInfoStruct -namespace LocationStruct { +namespace AreaStruct { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; - encoder.Encode(to_underlying(Fields::kLocationID), locationID); + encoder.Encode(to_underlying(Fields::kAreaID), areaID); encoder.Encode(to_underlying(Fields::kMapID), mapID); - encoder.Encode(to_underlying(Fields::kLocationInfo), locationInfo); + encoder.Encode(to_underlying(Fields::kAreaDesc), areaDesc); return encoder.Finalize(); } @@ -20391,17 +20391,17 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) CHIP_ERROR err = CHIP_NO_ERROR; const uint8_t __context_tag = std::get(__element); - if (__context_tag == to_underlying(Fields::kLocationID)) + if (__context_tag == to_underlying(Fields::kAreaID)) { - err = DataModel::Decode(reader, locationID); + err = DataModel::Decode(reader, areaID); } else if (__context_tag == to_underlying(Fields::kMapID)) { err = DataModel::Decode(reader, mapID); } - else if (__context_tag == to_underlying(Fields::kLocationInfo)) + else if (__context_tag == to_underlying(Fields::kAreaDesc)) { - err = DataModel::Decode(reader, locationInfo); + err = DataModel::Decode(reader, areaDesc); } else { @@ -20411,7 +20411,7 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) } } -} // namespace LocationStruct +} // namespace AreaStruct namespace MapStruct { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const @@ -20458,7 +20458,7 @@ namespace ProgressStruct { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; - encoder.Encode(to_underlying(Fields::kLocationID), locationID); + encoder.Encode(to_underlying(Fields::kAreaID), areaID); encoder.Encode(to_underlying(Fields::kStatus), status); encoder.Encode(to_underlying(Fields::kTotalOperationalTime), totalOperationalTime); encoder.Encode(to_underlying(Fields::kEstimatedTime), estimatedTime); @@ -20479,9 +20479,9 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) CHIP_ERROR err = CHIP_NO_ERROR; const uint8_t __context_tag = std::get(__element); - if (__context_tag == to_underlying(Fields::kLocationID)) + if (__context_tag == to_underlying(Fields::kAreaID)) { - err = DataModel::Decode(reader, locationID); + err = DataModel::Decode(reader, areaID); } else if (__context_tag == to_underlying(Fields::kStatus)) { @@ -20507,11 +20507,11 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) } // namespace Structs namespace Commands { -namespace SelectLocations { +namespace SelectAreas { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; - encoder.Encode(to_underlying(Fields::kNewLocations), newLocations); + encoder.Encode(to_underlying(Fields::kNewAreas), newAreas); return encoder.Finalize(); } @@ -20529,9 +20529,9 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) CHIP_ERROR err = CHIP_NO_ERROR; const uint8_t __context_tag = std::get(__element); - if (__context_tag == to_underlying(Fields::kNewLocations)) + if (__context_tag == to_underlying(Fields::kNewAreas)) { - err = DataModel::Decode(reader, newLocations); + err = DataModel::Decode(reader, newAreas); } else { @@ -20540,8 +20540,8 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) ReturnErrorOnFailure(err); } } -} // namespace SelectLocations. -namespace SelectLocationsResponse { +} // namespace SelectAreas. +namespace SelectAreasResponse { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; @@ -20579,8 +20579,8 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) ReturnErrorOnFailure(err); } } -} // namespace SelectLocationsResponse. -namespace SkipCurrentLocation { +} // namespace SelectAreasResponse. +namespace SkipArea { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; @@ -20599,8 +20599,8 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) } } } -} // namespace SkipCurrentLocation. -namespace SkipCurrentLocationResponse { +} // namespace SkipArea. +namespace SkipAreaResponse { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; @@ -20638,7 +20638,7 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) ReturnErrorOnFailure(err); } } -} // namespace SkipCurrentLocationResponse. +} // namespace SkipAreaResponse. } // namespace Commands namespace Attributes { @@ -20646,14 +20646,14 @@ CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const Concre { switch (path.mAttributeId) { - case Attributes::SupportedLocations::TypeInfo::GetAttributeId(): - return DataModel::Decode(reader, supportedLocations); + case Attributes::SupportedAreas::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, supportedAreas); case Attributes::SupportedMaps::TypeInfo::GetAttributeId(): return DataModel::Decode(reader, supportedMaps); - case Attributes::SelectedLocations::TypeInfo::GetAttributeId(): - return DataModel::Decode(reader, selectedLocations); - case Attributes::CurrentLocation::TypeInfo::GetAttributeId(): - return DataModel::Decode(reader, currentLocation); + case Attributes::SelectedAreas::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, selectedAreas); + case Attributes::CurrentArea::TypeInfo::GetAttributeId(): + return DataModel::Decode(reader, currentArea); case Attributes::EstimatedEndTime::TypeInfo::GetAttributeId(): return DataModel::Decode(reader, estimatedEndTime); case Attributes::Progress::TypeInfo::GetAttributeId(): diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index 7ecd2334890ad8..a32e7aed4a13de 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -28320,7 +28320,7 @@ struct TypeInfo } // namespace BarrierControl namespace ServiceArea { namespace Structs { -namespace LocationInfoStruct { +namespace AreaInfoStruct { enum class Fields : uint8_t { kLocationInfo = 0, @@ -28346,21 +28346,21 @@ struct Type using DecodableType = Type; -} // namespace LocationInfoStruct -namespace LocationStruct { +} // namespace AreaInfoStruct +namespace AreaStruct { enum class Fields : uint8_t { - kLocationID = 0, - kMapID = 1, - kLocationInfo = 2, + kAreaID = 0, + kMapID = 1, + kAreaDesc = 2, }; struct Type { public: - uint32_t locationID = static_cast(0); + uint32_t areaID = static_cast(0); DataModel::Nullable mapID; - Structs::LocationInfoStruct::Type locationInfo; + Structs::AreaInfoStruct::Type areaDesc; CHIP_ERROR Decode(TLV::TLVReader & reader); @@ -28371,7 +28371,7 @@ struct Type using DecodableType = Type; -} // namespace LocationStruct +} // namespace AreaStruct namespace MapStruct { enum class Fields : uint8_t { @@ -28398,7 +28398,7 @@ using DecodableType = Type; namespace ProgressStruct { enum class Fields : uint8_t { - kLocationID = 0, + kAreaID = 0, kStatus = 1, kTotalOperationalTime = 2, kEstimatedTime = 3, @@ -28407,7 +28407,7 @@ enum class Fields : uint8_t struct Type { public: - uint32_t locationID = static_cast(0); + uint32_t areaID = static_cast(0); OperationalStatusEnum status = static_cast(0); Optional> totalOperationalTime; Optional> estimatedTime; @@ -28427,47 +28427,47 @@ using DecodableType = Type; namespace Commands { // Forward-declarations so we can reference these later. -namespace SelectLocations { +namespace SelectAreas { struct Type; struct DecodableType; -} // namespace SelectLocations +} // namespace SelectAreas -namespace SelectLocationsResponse { +namespace SelectAreasResponse { struct Type; struct DecodableType; -} // namespace SelectLocationsResponse +} // namespace SelectAreasResponse -namespace SkipCurrentLocation { +namespace SkipArea { struct Type; struct DecodableType; -} // namespace SkipCurrentLocation +} // namespace SkipArea -namespace SkipCurrentLocationResponse { +namespace SkipAreaResponse { struct Type; struct DecodableType; -} // namespace SkipCurrentLocationResponse +} // namespace SkipAreaResponse } // namespace Commands namespace Commands { -namespace SelectLocations { +namespace SelectAreas { enum class Fields : uint8_t { - kNewLocations = 0, + kNewAreas = 0, }; struct Type { public: // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand - static constexpr CommandId GetCommandId() { return Commands::SelectLocations::Id; } + static constexpr CommandId GetCommandId() { return Commands::SelectAreas::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } - DataModel::Nullable> newLocations; + DataModel::Nullable> newAreas; CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; - using ResponseType = Clusters::ServiceArea::Commands::SelectLocationsResponse::DecodableType; + using ResponseType = Clusters::ServiceArea::Commands::SelectAreasResponse::DecodableType; static constexpr bool MustUseTimedInvoke() { return false; } }; @@ -28475,14 +28475,14 @@ struct Type struct DecodableType { public: - static constexpr CommandId GetCommandId() { return Commands::SelectLocations::Id; } + static constexpr CommandId GetCommandId() { return Commands::SelectAreas::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } - DataModel::Nullable> newLocations; + DataModel::Nullable> newAreas; CHIP_ERROR Decode(TLV::TLVReader & reader); }; -}; // namespace SelectLocations -namespace SelectLocationsResponse { +}; // namespace SelectAreas +namespace SelectAreasResponse { enum class Fields : uint8_t { kStatus = 0, @@ -28493,10 +28493,10 @@ struct Type { public: // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand - static constexpr CommandId GetCommandId() { return Commands::SelectLocationsResponse::Id; } + static constexpr CommandId GetCommandId() { return Commands::SelectAreasResponse::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } - SelectLocationsStatus status = static_cast(0); + SelectAreasStatus status = static_cast(0); Optional statusText; CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; @@ -28509,15 +28509,15 @@ struct Type struct DecodableType { public: - static constexpr CommandId GetCommandId() { return Commands::SelectLocationsResponse::Id; } + static constexpr CommandId GetCommandId() { return Commands::SelectAreasResponse::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } - SelectLocationsStatus status = static_cast(0); + SelectAreasStatus status = static_cast(0); Optional statusText; CHIP_ERROR Decode(TLV::TLVReader & reader); }; -}; // namespace SelectLocationsResponse -namespace SkipCurrentLocation { +}; // namespace SelectAreasResponse +namespace SkipArea { enum class Fields : uint8_t { }; @@ -28526,12 +28526,12 @@ struct Type { public: // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand - static constexpr CommandId GetCommandId() { return Commands::SkipCurrentLocation::Id; } + static constexpr CommandId GetCommandId() { return Commands::SkipArea::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; - using ResponseType = Clusters::ServiceArea::Commands::SkipCurrentLocationResponse::DecodableType; + using ResponseType = Clusters::ServiceArea::Commands::SkipAreaResponse::DecodableType; static constexpr bool MustUseTimedInvoke() { return false; } }; @@ -28539,13 +28539,13 @@ struct Type struct DecodableType { public: - static constexpr CommandId GetCommandId() { return Commands::SkipCurrentLocation::Id; } + static constexpr CommandId GetCommandId() { return Commands::SkipArea::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } CHIP_ERROR Decode(TLV::TLVReader & reader); }; -}; // namespace SkipCurrentLocation -namespace SkipCurrentLocationResponse { +}; // namespace SkipArea +namespace SkipAreaResponse { enum class Fields : uint8_t { kStatus = 0, @@ -28556,10 +28556,10 @@ struct Type { public: // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand - static constexpr CommandId GetCommandId() { return Commands::SkipCurrentLocationResponse::Id; } + static constexpr CommandId GetCommandId() { return Commands::SkipAreaResponse::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } - SkipCurrentLocationStatus status = static_cast(0); + SkipAreaStatus status = static_cast(0); Optional statusText; CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; @@ -28572,32 +28572,31 @@ struct Type struct DecodableType { public: - static constexpr CommandId GetCommandId() { return Commands::SkipCurrentLocationResponse::Id; } + static constexpr CommandId GetCommandId() { return Commands::SkipAreaResponse::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } - SkipCurrentLocationStatus status = static_cast(0); + SkipAreaStatus status = static_cast(0); Optional statusText; CHIP_ERROR Decode(TLV::TLVReader & reader); }; -}; // namespace SkipCurrentLocationResponse +}; // namespace SkipAreaResponse } // namespace Commands namespace Attributes { -namespace SupportedLocations { +namespace SupportedAreas { struct TypeInfo { - using Type = chip::app::DataModel::List; - using DecodableType = - chip::app::DataModel::DecodableList; + using Type = chip::app::DataModel::List; + using DecodableType = chip::app::DataModel::DecodableList; using DecodableArgType = - const chip::app::DataModel::DecodableList &; + const chip::app::DataModel::DecodableList &; static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } - static constexpr AttributeId GetAttributeId() { return Attributes::SupportedLocations::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::SupportedAreas::Id; } static constexpr bool MustUseTimedWrite() { return false; } }; -} // namespace SupportedLocations +} // namespace SupportedAreas namespace SupportedMaps { struct TypeInfo { @@ -28613,7 +28612,7 @@ struct TypeInfo static constexpr bool MustUseTimedWrite() { return false; } }; } // namespace SupportedMaps -namespace SelectedLocations { +namespace SelectedAreas { struct TypeInfo { using Type = chip::app::DataModel::Nullable>; @@ -28621,11 +28620,11 @@ struct TypeInfo using DecodableArgType = const chip::app::DataModel::Nullable> &; static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } - static constexpr AttributeId GetAttributeId() { return Attributes::SelectedLocations::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::SelectedAreas::Id; } static constexpr bool MustUseTimedWrite() { return false; } }; -} // namespace SelectedLocations -namespace CurrentLocation { +} // namespace SelectedAreas +namespace CurrentArea { struct TypeInfo { using Type = chip::app::DataModel::Nullable; @@ -28633,10 +28632,10 @@ struct TypeInfo using DecodableArgType = const chip::app::DataModel::Nullable &; static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } - static constexpr AttributeId GetAttributeId() { return Attributes::CurrentLocation::Id; } + static constexpr AttributeId GetAttributeId() { return Attributes::CurrentArea::Id; } static constexpr bool MustUseTimedWrite() { return false; } }; -} // namespace CurrentLocation +} // namespace CurrentArea namespace EstimatedEndTime { struct TypeInfo { @@ -28709,10 +28708,10 @@ struct TypeInfo CHIP_ERROR Decode(TLV::TLVReader & reader, const ConcreteAttributePath & path); - Attributes::SupportedLocations::TypeInfo::DecodableType supportedLocations; + Attributes::SupportedAreas::TypeInfo::DecodableType supportedAreas; Attributes::SupportedMaps::TypeInfo::DecodableType supportedMaps; - Attributes::SelectedLocations::TypeInfo::DecodableType selectedLocations; - Attributes::CurrentLocation::TypeInfo::DecodableType currentLocation; + Attributes::SelectedAreas::TypeInfo::DecodableType selectedAreas; + Attributes::CurrentArea::TypeInfo::DecodableType currentArea; Attributes::EstimatedEndTime::TypeInfo::DecodableType estimatedEndTime; Attributes::Progress::TypeInfo::DecodableType progress; Attributes::GeneratedCommandList::TypeInfo::DecodableType generatedCommandList; diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h index 5deab64ef504fc..7bd5d877f69897 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h @@ -4798,21 +4798,21 @@ static constexpr AttributeId Id = Globals::Attributes::ClusterRevision::Id; namespace ServiceArea { namespace Attributes { -namespace SupportedLocations { +namespace SupportedAreas { static constexpr AttributeId Id = 0x00000000; -} // namespace SupportedLocations +} // namespace SupportedAreas namespace SupportedMaps { static constexpr AttributeId Id = 0x00000001; } // namespace SupportedMaps -namespace SelectedLocations { +namespace SelectedAreas { static constexpr AttributeId Id = 0x00000002; -} // namespace SelectedLocations +} // namespace SelectedAreas -namespace CurrentLocation { +namespace CurrentArea { static constexpr AttributeId Id = 0x00000003; -} // namespace CurrentLocation +} // namespace CurrentArea namespace EstimatedEndTime { static constexpr AttributeId Id = 0x00000004; diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h index e9210638315112..e5948484cb568a 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h @@ -1298,21 +1298,21 @@ static constexpr CommandId Id = 0x00000001; namespace ServiceArea { namespace Commands { -namespace SelectLocations { +namespace SelectAreas { static constexpr CommandId Id = 0x00000000; -} // namespace SelectLocations +} // namespace SelectAreas -namespace SelectLocationsResponse { +namespace SelectAreasResponse { static constexpr CommandId Id = 0x00000001; -} // namespace SelectLocationsResponse +} // namespace SelectAreasResponse -namespace SkipCurrentLocation { +namespace SkipArea { static constexpr CommandId Id = 0x00000002; -} // namespace SkipCurrentLocation +} // namespace SkipArea -namespace SkipCurrentLocationResponse { +namespace SkipAreaResponse { static constexpr CommandId Id = 0x00000003; -} // namespace SkipCurrentLocationResponse +} // namespace SkipAreaResponse } // namespace Commands } // namespace ServiceArea diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index a48a4b5376f2b7..1fb3e0ccaab559 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -9362,14 +9362,14 @@ class BarrierControlBarrierControlStop : public ClusterCommand | Cluster ServiceArea | 0x0150 | |------------------------------------------------------------------------------| | Commands: | | -| * SelectLocations | 0x00 | -| * SkipCurrentLocation | 0x02 | +| * SelectAreas | 0x00 | +| * SkipArea | 0x02 | |------------------------------------------------------------------------------| | Attributes: | | -| * SupportedLocations | 0x0000 | +| * SupportedAreas | 0x0000 | | * SupportedMaps | 0x0001 | -| * SelectedLocations | 0x0002 | -| * CurrentLocation | 0x0003 | +| * SelectedAreas | 0x0002 | +| * CurrentArea | 0x0003 | | * EstimatedEndTime | 0x0004 | | * Progress | 0x0005 | | * GeneratedCommandList | 0xFFF8 | @@ -9383,22 +9383,22 @@ class BarrierControlBarrierControlStop : public ClusterCommand \*----------------------------------------------------------------------------*/ /* - * Command SelectLocations + * Command SelectAreas */ -class ServiceAreaSelectLocations : public ClusterCommand +class ServiceAreaSelectAreas : public ClusterCommand { public: - ServiceAreaSelectLocations(CredentialIssuerCommands * credsIssuerConfig) : - ClusterCommand("select-locations", credsIssuerConfig), mComplex_NewLocations(&mRequest.newLocations) + ServiceAreaSelectAreas(CredentialIssuerCommands * credsIssuerConfig) : + ClusterCommand("select-areas", credsIssuerConfig), mComplex_NewAreas(&mRequest.newAreas) { - AddArgument("NewLocations", &mComplex_NewLocations); + AddArgument("NewAreas", &mComplex_NewAreas); ClusterCommand::AddArguments(); } CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::ServiceArea::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::ServiceArea::Commands::SelectLocations::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::ServiceArea::Commands::SelectAreas::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointIds.at(0)); @@ -9408,7 +9408,7 @@ class ServiceAreaSelectLocations : public ClusterCommand CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::ServiceArea::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::ServiceArea::Commands::SelectLocations::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::ServiceArea::Commands::SelectAreas::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on Group %u", clusterId, commandId, groupId); @@ -9417,18 +9417,17 @@ class ServiceAreaSelectLocations : public ClusterCommand } private: - chip::app::Clusters::ServiceArea::Commands::SelectLocations::Type mRequest; - TypedComplexArgument>> mComplex_NewLocations; + chip::app::Clusters::ServiceArea::Commands::SelectAreas::Type mRequest; + TypedComplexArgument>> mComplex_NewAreas; }; /* - * Command SkipCurrentLocation + * Command SkipArea */ -class ServiceAreaSkipCurrentLocation : public ClusterCommand +class ServiceAreaSkipArea : public ClusterCommand { public: - ServiceAreaSkipCurrentLocation(CredentialIssuerCommands * credsIssuerConfig) : - ClusterCommand("skip-current-location", credsIssuerConfig) + ServiceAreaSkipArea(CredentialIssuerCommands * credsIssuerConfig) : ClusterCommand("skip-area", credsIssuerConfig) { ClusterCommand::AddArguments(); } @@ -9436,7 +9435,7 @@ class ServiceAreaSkipCurrentLocation : public ClusterCommand CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::ServiceArea::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::ServiceArea::Commands::SkipCurrentLocation::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::ServiceArea::Commands::SkipArea::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointIds.at(0)); @@ -9446,7 +9445,7 @@ class ServiceAreaSkipCurrentLocation : public ClusterCommand CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::ServiceArea::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::ServiceArea::Commands::SkipCurrentLocation::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::ServiceArea::Commands::SkipArea::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on Group %u", clusterId, commandId, groupId); @@ -9455,7 +9454,7 @@ class ServiceAreaSkipCurrentLocation : public ClusterCommand } private: - chip::app::Clusters::ServiceArea::Commands::SkipCurrentLocation::Type mRequest; + chip::app::Clusters::ServiceArea::Commands::SkipArea::Type mRequest; }; /*----------------------------------------------------------------------------*\ @@ -22846,17 +22845,17 @@ void registerClusterServiceArea(Commands & commands, CredentialIssuerCommands * // // Commands // - make_unique(Id, credsIssuerConfig), // - make_unique(credsIssuerConfig), // - make_unique(credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // + make_unique(credsIssuerConfig), // + make_unique(credsIssuerConfig), // // // Attributes // make_unique(Id, credsIssuerConfig), // - make_unique(Id, "supported-locations", Attributes::SupportedLocations::Id, credsIssuerConfig), // + make_unique(Id, "supported-areas", Attributes::SupportedAreas::Id, credsIssuerConfig), // make_unique(Id, "supported-maps", Attributes::SupportedMaps::Id, credsIssuerConfig), // - make_unique(Id, "selected-locations", Attributes::SelectedLocations::Id, credsIssuerConfig), // - make_unique(Id, "current-location", Attributes::CurrentLocation::Id, credsIssuerConfig), // + make_unique(Id, "selected-areas", Attributes::SelectedAreas::Id, credsIssuerConfig), // + make_unique(Id, "current-area", Attributes::CurrentArea::Id, credsIssuerConfig), // make_unique(Id, "estimated-end-time", Attributes::EstimatedEndTime::Id, credsIssuerConfig), // make_unique(Id, "progress", Attributes::Progress::Id, credsIssuerConfig), // make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // @@ -22866,17 +22865,16 @@ void registerClusterServiceArea(Commands & commands, CredentialIssuerCommands * make_unique(Id, "feature-map", Attributes::FeatureMap::Id, credsIssuerConfig), // make_unique(Id, "cluster-revision", Attributes::ClusterRevision::Id, credsIssuerConfig), // make_unique>(Id, credsIssuerConfig), // - make_unique>>( - Id, "supported-locations", Attributes::SupportedLocations::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique< + WriteAttributeAsComplex>>( + Id, "supported-areas", Attributes::SupportedAreas::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>>>( Id, "supported-maps", Attributes::SupportedMaps::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>>>( - Id, "selected-locations", Attributes::SelectedLocations::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>>(Id, "current-location", 0, UINT32_MAX, - Attributes::CurrentLocation::Id, - WriteCommandType::kForceWrite, credsIssuerConfig), // + Id, "selected-areas", Attributes::SelectedAreas::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "current-area", 0, UINT32_MAX, Attributes::CurrentArea::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>>(Id, "estimated-end-time", 0, UINT32_MAX, Attributes::EstimatedEndTime::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // @@ -22897,10 +22895,10 @@ void registerClusterServiceArea(Commands & commands, CredentialIssuerCommands * make_unique>(Id, "cluster-revision", 0, UINT16_MAX, Attributes::ClusterRevision::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique(Id, credsIssuerConfig), // - make_unique(Id, "supported-locations", Attributes::SupportedLocations::Id, credsIssuerConfig), // + make_unique(Id, "supported-areas", Attributes::SupportedAreas::Id, credsIssuerConfig), // make_unique(Id, "supported-maps", Attributes::SupportedMaps::Id, credsIssuerConfig), // - make_unique(Id, "selected-locations", Attributes::SelectedLocations::Id, credsIssuerConfig), // - make_unique(Id, "current-location", Attributes::CurrentLocation::Id, credsIssuerConfig), // + make_unique(Id, "selected-areas", Attributes::SelectedAreas::Id, credsIssuerConfig), // + make_unique(Id, "current-area", Attributes::CurrentArea::Id, credsIssuerConfig), // make_unique(Id, "estimated-end-time", Attributes::EstimatedEndTime::Id, credsIssuerConfig), // make_unique(Id, "progress", Attributes::Progress::Id, credsIssuerConfig), // make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // diff --git a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp index 32b3967affe64e..51a2d775b6e94c 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp @@ -3943,7 +3943,7 @@ void ComplexArgumentParser::Finalize(chip::app::Clusters::DoorLock::Structs::Cre } CHIP_ERROR ComplexArgumentParser::Setup(const char * label, - chip::app::Clusters::ServiceArea::Structs::LocationInfoStruct::Type & request, + chip::app::Clusters::ServiceArea::Structs::AreaInfoStruct::Type & request, Json::Value & value) { VerifyOrReturnError(value.isObject(), CHIP_ERROR_INVALID_ARGUMENT); @@ -3951,14 +3951,14 @@ CHIP_ERROR ComplexArgumentParser::Setup(const char * label, // Copy to track which members we already processed. Json::Value valueCopy(value); - ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("LocationInfoStruct.locationInfo", "locationInfo", - value.isMember("locationInfo"))); ReturnErrorOnFailure( - ComplexArgumentParser::EnsureMemberExist("LocationInfoStruct.landmarkTag", "landmarkTag", value.isMember("landmarkTag"))); + ComplexArgumentParser::EnsureMemberExist("AreaInfoStruct.locationInfo", "locationInfo", value.isMember("locationInfo"))); ReturnErrorOnFailure( - ComplexArgumentParser::EnsureMemberExist("LocationInfoStruct.positionTag", "positionTag", value.isMember("positionTag"))); + ComplexArgumentParser::EnsureMemberExist("AreaInfoStruct.landmarkTag", "landmarkTag", value.isMember("landmarkTag"))); ReturnErrorOnFailure( - ComplexArgumentParser::EnsureMemberExist("LocationInfoStruct.surfaceTag", "surfaceTag", value.isMember("surfaceTag"))); + ComplexArgumentParser::EnsureMemberExist("AreaInfoStruct.positionTag", "positionTag", value.isMember("positionTag"))); + ReturnErrorOnFailure( + ComplexArgumentParser::EnsureMemberExist("AreaInfoStruct.surfaceTag", "surfaceTag", value.isMember("surfaceTag"))); char labelWithMember[kMaxLabelLength]; snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "locationInfo"); @@ -3980,7 +3980,7 @@ CHIP_ERROR ComplexArgumentParser::Setup(const char * label, return ComplexArgumentParser::EnsureNoMembersRemaining(label, valueCopy); } -void ComplexArgumentParser::Finalize(chip::app::Clusters::ServiceArea::Structs::LocationInfoStruct::Type & request) +void ComplexArgumentParser::Finalize(chip::app::Clusters::ServiceArea::Structs::AreaInfoStruct::Type & request) { ComplexArgumentParser::Finalize(request.locationInfo); ComplexArgumentParser::Finalize(request.landmarkTag); @@ -3988,8 +3988,7 @@ void ComplexArgumentParser::Finalize(chip::app::Clusters::ServiceArea::Structs:: ComplexArgumentParser::Finalize(request.surfaceTag); } -CHIP_ERROR ComplexArgumentParser::Setup(const char * label, - chip::app::Clusters::ServiceArea::Structs::LocationStruct::Type & request, +CHIP_ERROR ComplexArgumentParser::Setup(const char * label, chip::app::Clusters::ServiceArea::Structs::AreaStruct::Type & request, Json::Value & value) { VerifyOrReturnError(value.isObject(), CHIP_ERROR_INVALID_ARGUMENT); @@ -3997,33 +3996,31 @@ CHIP_ERROR ComplexArgumentParser::Setup(const char * label, // Copy to track which members we already processed. Json::Value valueCopy(value); - ReturnErrorOnFailure( - ComplexArgumentParser::EnsureMemberExist("LocationStruct.locationID", "locationID", value.isMember("locationID"))); - ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("LocationStruct.mapID", "mapID", value.isMember("mapID"))); - ReturnErrorOnFailure( - ComplexArgumentParser::EnsureMemberExist("LocationStruct.locationInfo", "locationInfo", value.isMember("locationInfo"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("AreaStruct.areaID", "areaID", value.isMember("areaID"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("AreaStruct.mapID", "mapID", value.isMember("mapID"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("AreaStruct.areaDesc", "areaDesc", value.isMember("areaDesc"))); char labelWithMember[kMaxLabelLength]; - snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "locationID"); - ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.locationID, value["locationID"])); - valueCopy.removeMember("locationID"); + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "areaID"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.areaID, value["areaID"])); + valueCopy.removeMember("areaID"); snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "mapID"); ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.mapID, value["mapID"])); valueCopy.removeMember("mapID"); - snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "locationInfo"); - ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.locationInfo, value["locationInfo"])); - valueCopy.removeMember("locationInfo"); + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "areaDesc"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.areaDesc, value["areaDesc"])); + valueCopy.removeMember("areaDesc"); return ComplexArgumentParser::EnsureNoMembersRemaining(label, valueCopy); } -void ComplexArgumentParser::Finalize(chip::app::Clusters::ServiceArea::Structs::LocationStruct::Type & request) +void ComplexArgumentParser::Finalize(chip::app::Clusters::ServiceArea::Structs::AreaStruct::Type & request) { - ComplexArgumentParser::Finalize(request.locationID); + ComplexArgumentParser::Finalize(request.areaID); ComplexArgumentParser::Finalize(request.mapID); - ComplexArgumentParser::Finalize(request.locationInfo); + ComplexArgumentParser::Finalize(request.areaDesc); } CHIP_ERROR ComplexArgumentParser::Setup(const char * label, chip::app::Clusters::ServiceArea::Structs::MapStruct::Type & request, @@ -4064,14 +4061,13 @@ CHIP_ERROR ComplexArgumentParser::Setup(const char * label, // Copy to track which members we already processed. Json::Value valueCopy(value); - ReturnErrorOnFailure( - ComplexArgumentParser::EnsureMemberExist("ProgressStruct.locationID", "locationID", value.isMember("locationID"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("ProgressStruct.areaID", "areaID", value.isMember("areaID"))); ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("ProgressStruct.status", "status", value.isMember("status"))); char labelWithMember[kMaxLabelLength]; - snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "locationID"); - ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.locationID, value["locationID"])); - valueCopy.removeMember("locationID"); + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "areaID"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.areaID, value["areaID"])); + valueCopy.removeMember("areaID"); snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "status"); ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.status, value["status"])); @@ -4097,7 +4093,7 @@ CHIP_ERROR ComplexArgumentParser::Setup(const char * label, void ComplexArgumentParser::Finalize(chip::app::Clusters::ServiceArea::Structs::ProgressStruct::Type & request) { - ComplexArgumentParser::Finalize(request.locationID); + ComplexArgumentParser::Finalize(request.areaID); ComplexArgumentParser::Finalize(request.status); ComplexArgumentParser::Finalize(request.totalOperationalTime); ComplexArgumentParser::Finalize(request.estimatedTime); diff --git a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.h b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.h index 82c9b590eb2920..14d10ae89ba82b 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.h @@ -453,15 +453,15 @@ static CHIP_ERROR Setup(const char * label, chip::app::Clusters::DoorLock::Struc static void Finalize(chip::app::Clusters::DoorLock::Structs::CredentialStruct::Type & request); -static CHIP_ERROR Setup(const char * label, chip::app::Clusters::ServiceArea::Structs::LocationInfoStruct::Type & request, +static CHIP_ERROR Setup(const char * label, chip::app::Clusters::ServiceArea::Structs::AreaInfoStruct::Type & request, Json::Value & value); -static void Finalize(chip::app::Clusters::ServiceArea::Structs::LocationInfoStruct::Type & request); +static void Finalize(chip::app::Clusters::ServiceArea::Structs::AreaInfoStruct::Type & request); -static CHIP_ERROR Setup(const char * label, chip::app::Clusters::ServiceArea::Structs::LocationStruct::Type & request, +static CHIP_ERROR Setup(const char * label, chip::app::Clusters::ServiceArea::Structs::AreaStruct::Type & request, Json::Value & value); -static void Finalize(chip::app::Clusters::ServiceArea::Structs::LocationStruct::Type & request); +static void Finalize(chip::app::Clusters::ServiceArea::Structs::AreaStruct::Type & request); static CHIP_ERROR Setup(const char * label, chip::app::Clusters::ServiceArea::Structs::MapStruct::Type & request, Json::Value & value); diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp index c0b553ca7103bb..de22cae0e0346c 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp @@ -3490,7 +3490,7 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, } CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, - const chip::app::Clusters::ServiceArea::Structs::LocationInfoStruct::DecodableType & value) + const chip::app::Clusters::ServiceArea::Structs::AreaInfoStruct::DecodableType & value) { DataModelLogger::LogString(label, indent, "{"); { @@ -3531,14 +3531,14 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, } CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, - const chip::app::Clusters::ServiceArea::Structs::LocationStruct::DecodableType & value) + const chip::app::Clusters::ServiceArea::Structs::AreaStruct::DecodableType & value) { DataModelLogger::LogString(label, indent, "{"); { - CHIP_ERROR err = LogValue("LocationID", indent + 1, value.locationID); + CHIP_ERROR err = LogValue("AreaID", indent + 1, value.areaID); if (err != CHIP_NO_ERROR) { - DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'LocationID'"); + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'AreaID'"); return err; } } @@ -3551,10 +3551,10 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, } } { - CHIP_ERROR err = LogValue("LocationInfo", indent + 1, value.locationInfo); + CHIP_ERROR err = LogValue("AreaDesc", indent + 1, value.areaDesc); if (err != CHIP_NO_ERROR) { - DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'LocationInfo'"); + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'AreaDesc'"); return err; } } @@ -3593,10 +3593,10 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, { DataModelLogger::LogString(label, indent, "{"); { - CHIP_ERROR err = LogValue("LocationID", indent + 1, value.locationID); + CHIP_ERROR err = LogValue("AreaID", indent + 1, value.areaID); if (err != CHIP_NO_ERROR) { - DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'LocationID'"); + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'AreaID'"); return err; } } @@ -8442,7 +8442,7 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, return CHIP_NO_ERROR; } CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, - const ServiceArea::Commands::SelectLocationsResponse::DecodableType & value) + const ServiceArea::Commands::SelectAreasResponse::DecodableType & value) { DataModelLogger::LogString(label, indent, "{"); ReturnErrorOnFailure(DataModelLogger::LogValue("status", indent + 1, value.status)); @@ -8451,7 +8451,7 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, return CHIP_NO_ERROR; } CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, - const ServiceArea::Commands::SkipCurrentLocationResponse::DecodableType & value) + const ServiceArea::Commands::SkipAreaResponse::DecodableType & value) { DataModelLogger::LogString(label, indent, "{"); ReturnErrorOnFailure(DataModelLogger::LogValue("status", indent + 1, value.status)); @@ -14697,10 +14697,10 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP case ServiceArea::Id: { switch (path.mAttributeId) { - case ServiceArea::Attributes::SupportedLocations::Id: { - chip::app::DataModel::DecodableList value; + case ServiceArea::Attributes::SupportedAreas::Id: { + chip::app::DataModel::DecodableList value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); - return DataModelLogger::LogValue("SupportedLocations", 1, value); + return DataModelLogger::LogValue("SupportedAreas", 1, value); } case ServiceArea::Attributes::SupportedMaps::Id: { chip::app::DataModel::Nullable< @@ -14709,15 +14709,15 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("SupportedMaps", 1, value); } - case ServiceArea::Attributes::SelectedLocations::Id: { + case ServiceArea::Attributes::SelectedAreas::Id: { chip::app::DataModel::Nullable> value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); - return DataModelLogger::LogValue("SelectedLocations", 1, value); + return DataModelLogger::LogValue("SelectedAreas", 1, value); } - case ServiceArea::Attributes::CurrentLocation::Id: { + case ServiceArea::Attributes::CurrentArea::Id: { chip::app::DataModel::Nullable value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); - return DataModelLogger::LogValue("CurrentLocation", 1, value); + return DataModelLogger::LogValue("CurrentArea", 1, value); } case ServiceArea::Attributes::EstimatedEndTime::Id: { chip::app::DataModel::Nullable value; @@ -19775,15 +19775,15 @@ CHIP_ERROR DataModelLogger::LogCommand(const chip::app::ConcreteCommandPath & pa case ServiceArea::Id: { switch (path.mCommandId) { - case ServiceArea::Commands::SelectLocationsResponse::Id: { - ServiceArea::Commands::SelectLocationsResponse::DecodableType value; + case ServiceArea::Commands::SelectAreasResponse::Id: { + ServiceArea::Commands::SelectAreasResponse::DecodableType value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); - return DataModelLogger::LogValue("SelectLocationsResponse", 1, value); + return DataModelLogger::LogValue("SelectAreasResponse", 1, value); } - case ServiceArea::Commands::SkipCurrentLocationResponse::Id: { - ServiceArea::Commands::SkipCurrentLocationResponse::DecodableType value; + case ServiceArea::Commands::SkipAreaResponse::Id: { + ServiceArea::Commands::SkipAreaResponse::DecodableType value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); - return DataModelLogger::LogValue("SkipCurrentLocationResponse", 1, value); + return DataModelLogger::LogValue("SkipAreaResponse", 1, value); } } break; diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h index c7a0a925fc11f3..7d7e961dcb16d3 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h @@ -284,10 +284,10 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::DoorLock::Structs::CredentialStruct::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, - const chip::app::Clusters::ServiceArea::Structs::LocationInfoStruct::DecodableType & value); + const chip::app::Clusters::ServiceArea::Structs::AreaInfoStruct::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, - const chip::app::Clusters::ServiceArea::Structs::LocationStruct::DecodableType & value); + const chip::app::Clusters::ServiceArea::Structs::AreaStruct::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::ServiceArea::Structs::MapStruct::DecodableType & value); @@ -793,9 +793,9 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::DoorLock::Commands::GetCredentialStatusResponse::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, - const chip::app::Clusters::ServiceArea::Commands::SelectLocationsResponse::DecodableType & value); + const chip::app::Clusters::ServiceArea::Commands::SelectAreasResponse::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, - const chip::app::Clusters::ServiceArea::Commands::SkipCurrentLocationResponse::DecodableType & value); + const chip::app::Clusters::ServiceArea::Commands::SkipAreaResponse::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::Thermostat::Commands::GetWeeklyScheduleResponse::DecodableType & value); static CHIP_ERROR diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index e226d87a19aec8..0643c1f99d09e4 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -103852,14 +103852,14 @@ class SubscribeAttributeBarrierControlClusterRevision : public SubscribeAttribut | Cluster ServiceArea | 0x0150 | |------------------------------------------------------------------------------| | Commands: | | -| * SelectLocations | 0x00 | -| * SkipCurrentLocation | 0x02 | +| * SelectAreas | 0x00 | +| * SkipArea | 0x02 | |------------------------------------------------------------------------------| | Attributes: | | -| * SupportedLocations | 0x0000 | +| * SupportedAreas | 0x0000 | | * SupportedMaps | 0x0001 | -| * SelectedLocations | 0x0002 | -| * CurrentLocation | 0x0003 | +| * SelectedAreas | 0x0002 | +| * CurrentArea | 0x0003 | | * EstimatedEndTime | 0x0004 | | * Progress | 0x0005 | | * GeneratedCommandList | 0xFFF8 | @@ -103874,16 +103874,16 @@ class SubscribeAttributeBarrierControlClusterRevision : public SubscribeAttribut #if MTR_ENABLE_PROVISIONAL /* - * Command SelectLocations + * Command SelectAreas */ -class ServiceAreaSelectLocations : public ClusterCommand { +class ServiceAreaSelectAreas : public ClusterCommand { public: - ServiceAreaSelectLocations() - : ClusterCommand("select-locations") - , mComplex_NewLocations(&mRequest.newLocations) + ServiceAreaSelectAreas() + : ClusterCommand("select-areas") + , mComplex_NewAreas(&mRequest.newAreas) { #if MTR_ENABLE_PROVISIONAL - AddArgument("NewLocations", &mComplex_NewLocations); + AddArgument("NewAreas", &mComplex_NewAreas); #endif // MTR_ENABLE_PROVISIONAL ClusterCommand::AddArguments(); } @@ -103891,68 +103891,68 @@ class ServiceAreaSelectLocations : public ClusterCommand { CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::ServiceArea::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::ServiceArea::Commands::SelectLocations::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::ServiceArea::Commands::SelectAreas::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); __auto_type * cluster = [[MTRBaseClusterServiceArea alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - __auto_type * params = [[MTRServiceAreaClusterSelectLocationsParams alloc] init]; + __auto_type * params = [[MTRServiceAreaClusterSelectAreasParams alloc] init]; params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; #if MTR_ENABLE_PROVISIONAL - if (mRequest.newLocations.IsNull()) { - params.newLocations = nil; + if (mRequest.newAreas.IsNull()) { + params.newAreas = nil; } else { { // Scope for our temporary variables auto * array_1 = [NSMutableArray new]; - for (auto & entry_1 : mRequest.newLocations.Value()) { + for (auto & entry_1 : mRequest.newAreas.Value()) { NSNumber * newElement_1; newElement_1 = [NSNumber numberWithUnsignedInt:entry_1]; [array_1 addObject:newElement_1]; } - params.newLocations = array_1; + params.newAreas = array_1; } } #endif // MTR_ENABLE_PROVISIONAL uint16_t repeatCount = mRepeatCount.ValueOr(1); uint16_t __block responsesNeeded = repeatCount; while (repeatCount--) { - [cluster selectLocationsWithParams:params completion: - ^(MTRServiceAreaClusterSelectLocationsResponseParams * _Nullable values, NSError * _Nullable error) { - NSLog(@"Values: %@", values); - if (error == nil) { - constexpr chip::CommandId responseId = chip::app::Clusters::ServiceArea::Commands::SelectLocationsResponse::Id; - RemoteDataModelLogger::LogCommandAsJSON(@(endpointId), @(clusterId), @(responseId), values); - } - responsesNeeded--; - if (error != nil) { - mError = error; - LogNSError("Error", error); - constexpr chip::CommandId responseId = chip::app::Clusters::ServiceArea::Commands::SelectLocationsResponse::Id; - RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(responseId), error); - } - if (responsesNeeded == 0) { - SetCommandExitStatus(mError); - } - }]; + [cluster selectAreasWithParams:params completion: + ^(MTRServiceAreaClusterSelectAreasResponseParams * _Nullable values, NSError * _Nullable error) { + NSLog(@"Values: %@", values); + if (error == nil) { + constexpr chip::CommandId responseId = chip::app::Clusters::ServiceArea::Commands::SelectAreasResponse::Id; + RemoteDataModelLogger::LogCommandAsJSON(@(endpointId), @(clusterId), @(responseId), values); + } + responsesNeeded--; + if (error != nil) { + mError = error; + LogNSError("Error", error); + constexpr chip::CommandId responseId = chip::app::Clusters::ServiceArea::Commands::SelectAreasResponse::Id; + RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(responseId), error); + } + if (responsesNeeded == 0) { + SetCommandExitStatus(mError); + } + }]; } return CHIP_NO_ERROR; } private: - chip::app::Clusters::ServiceArea::Commands::SelectLocations::Type mRequest; - TypedComplexArgument>> mComplex_NewLocations; + chip::app::Clusters::ServiceArea::Commands::SelectAreas::Type mRequest; + TypedComplexArgument>> mComplex_NewAreas; }; #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL /* - * Command SkipCurrentLocation + * Command SkipArea */ -class ServiceAreaSkipCurrentLocation : public ClusterCommand { +class ServiceAreaSkipArea : public ClusterCommand { public: - ServiceAreaSkipCurrentLocation() - : ClusterCommand("skip-current-location") + ServiceAreaSkipArea() + : ClusterCommand("skip-area") { ClusterCommand::AddArguments(); } @@ -103960,35 +103960,35 @@ class ServiceAreaSkipCurrentLocation : public ClusterCommand { CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::ServiceArea::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::ServiceArea::Commands::SkipCurrentLocation::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::ServiceArea::Commands::SkipArea::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); __auto_type * cluster = [[MTRBaseClusterServiceArea alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - __auto_type * params = [[MTRServiceAreaClusterSkipCurrentLocationParams alloc] init]; + __auto_type * params = [[MTRServiceAreaClusterSkipAreaParams alloc] init]; params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; uint16_t repeatCount = mRepeatCount.ValueOr(1); uint16_t __block responsesNeeded = repeatCount; while (repeatCount--) { - [cluster skipCurrentLocationWithParams:params completion: - ^(MTRServiceAreaClusterSkipCurrentLocationResponseParams * _Nullable values, NSError * _Nullable error) { - NSLog(@"Values: %@", values); - if (error == nil) { - constexpr chip::CommandId responseId = chip::app::Clusters::ServiceArea::Commands::SkipCurrentLocationResponse::Id; - RemoteDataModelLogger::LogCommandAsJSON(@(endpointId), @(clusterId), @(responseId), values); - } - responsesNeeded--; - if (error != nil) { - mError = error; - LogNSError("Error", error); - constexpr chip::CommandId responseId = chip::app::Clusters::ServiceArea::Commands::SkipCurrentLocationResponse::Id; - RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(responseId), error); - } - if (responsesNeeded == 0) { - SetCommandExitStatus(mError); - } - }]; + [cluster skipAreaWithParams:params completion: + ^(MTRServiceAreaClusterSkipAreaResponseParams * _Nullable values, NSError * _Nullable error) { + NSLog(@"Values: %@", values); + if (error == nil) { + constexpr chip::CommandId responseId = chip::app::Clusters::ServiceArea::Commands::SkipAreaResponse::Id; + RemoteDataModelLogger::LogCommandAsJSON(@(endpointId), @(clusterId), @(responseId), values); + } + responsesNeeded--; + if (error != nil) { + mError = error; + LogNSError("Error", error); + constexpr chip::CommandId responseId = chip::app::Clusters::ServiceArea::Commands::SkipAreaResponse::Id; + RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(responseId), error); + } + if (responsesNeeded == 0) { + SetCommandExitStatus(mError); + } + }]; } return CHIP_NO_ERROR; } @@ -104001,34 +104001,34 @@ class ServiceAreaSkipCurrentLocation : public ClusterCommand { #if MTR_ENABLE_PROVISIONAL /* - * Attribute SupportedLocations + * Attribute SupportedAreas */ -class ReadServiceAreaSupportedLocations : public ReadAttribute { +class ReadServiceAreaSupportedAreas : public ReadAttribute { public: - ReadServiceAreaSupportedLocations() - : ReadAttribute("supported-locations") + ReadServiceAreaSupportedAreas() + : ReadAttribute("supported-areas") { } - ~ReadServiceAreaSupportedLocations() + ~ReadServiceAreaSupportedAreas() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::ServiceArea::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::ServiceArea::Attributes::SupportedLocations::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::ServiceArea::Attributes::SupportedAreas::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); __auto_type * cluster = [[MTRBaseClusterServiceArea alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - [cluster readAttributeSupportedLocationsWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { - NSLog(@"ServiceArea.SupportedLocations response %@", [value description]); + [cluster readAttributeSupportedAreasWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"ServiceArea.SupportedAreas response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("ServiceArea SupportedLocations read Error", error); + LogNSError("ServiceArea SupportedAreas read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -104037,21 +104037,21 @@ class ReadServiceAreaSupportedLocations : public ReadAttribute { } }; -class SubscribeAttributeServiceAreaSupportedLocations : public SubscribeAttribute { +class SubscribeAttributeServiceAreaSupportedAreas : public SubscribeAttribute { public: - SubscribeAttributeServiceAreaSupportedLocations() - : SubscribeAttribute("supported-locations") + SubscribeAttributeServiceAreaSupportedAreas() + : SubscribeAttribute("supported-areas") { } - ~SubscribeAttributeServiceAreaSupportedLocations() + ~SubscribeAttributeServiceAreaSupportedAreas() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::ServiceArea::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::ServiceArea::Attributes::SupportedLocations::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::ServiceArea::Attributes::SupportedAreas::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); @@ -104066,10 +104066,10 @@ class SubscribeAttributeServiceAreaSupportedLocations : public SubscribeAttribut if (mAutoResubscribe.HasValue()) { params.resubscribeAutomatically = mAutoResubscribe.Value(); } - [cluster subscribeAttributeSupportedLocationsWithParams:params + [cluster subscribeAttributeSupportedAreasWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { - NSLog(@"ServiceArea.SupportedLocations response %@", [value description]); + NSLog(@"ServiceArea.SupportedAreas response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -104171,34 +104171,34 @@ class SubscribeAttributeServiceAreaSupportedMaps : public SubscribeAttribute { #if MTR_ENABLE_PROVISIONAL /* - * Attribute SelectedLocations + * Attribute SelectedAreas */ -class ReadServiceAreaSelectedLocations : public ReadAttribute { +class ReadServiceAreaSelectedAreas : public ReadAttribute { public: - ReadServiceAreaSelectedLocations() - : ReadAttribute("selected-locations") + ReadServiceAreaSelectedAreas() + : ReadAttribute("selected-areas") { } - ~ReadServiceAreaSelectedLocations() + ~ReadServiceAreaSelectedAreas() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::ServiceArea::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::ServiceArea::Attributes::SelectedLocations::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::ServiceArea::Attributes::SelectedAreas::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); __auto_type * cluster = [[MTRBaseClusterServiceArea alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - [cluster readAttributeSelectedLocationsWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { - NSLog(@"ServiceArea.SelectedLocations response %@", [value description]); + [cluster readAttributeSelectedAreasWithCompletion:^(NSArray * _Nullable value, NSError * _Nullable error) { + NSLog(@"ServiceArea.SelectedAreas response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("ServiceArea SelectedLocations read Error", error); + LogNSError("ServiceArea SelectedAreas read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -104207,21 +104207,21 @@ class ReadServiceAreaSelectedLocations : public ReadAttribute { } }; -class SubscribeAttributeServiceAreaSelectedLocations : public SubscribeAttribute { +class SubscribeAttributeServiceAreaSelectedAreas : public SubscribeAttribute { public: - SubscribeAttributeServiceAreaSelectedLocations() - : SubscribeAttribute("selected-locations") + SubscribeAttributeServiceAreaSelectedAreas() + : SubscribeAttribute("selected-areas") { } - ~SubscribeAttributeServiceAreaSelectedLocations() + ~SubscribeAttributeServiceAreaSelectedAreas() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::ServiceArea::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::ServiceArea::Attributes::SelectedLocations::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::ServiceArea::Attributes::SelectedAreas::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); @@ -104236,10 +104236,10 @@ class SubscribeAttributeServiceAreaSelectedLocations : public SubscribeAttribute if (mAutoResubscribe.HasValue()) { params.resubscribeAutomatically = mAutoResubscribe.Value(); } - [cluster subscribeAttributeSelectedLocationsWithParams:params + [cluster subscribeAttributeSelectedAreasWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSArray * _Nullable value, NSError * _Nullable error) { - NSLog(@"ServiceArea.SelectedLocations response %@", [value description]); + NSLog(@"ServiceArea.SelectedAreas response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -104256,34 +104256,34 @@ class SubscribeAttributeServiceAreaSelectedLocations : public SubscribeAttribute #if MTR_ENABLE_PROVISIONAL /* - * Attribute CurrentLocation + * Attribute CurrentArea */ -class ReadServiceAreaCurrentLocation : public ReadAttribute { +class ReadServiceAreaCurrentArea : public ReadAttribute { public: - ReadServiceAreaCurrentLocation() - : ReadAttribute("current-location") + ReadServiceAreaCurrentArea() + : ReadAttribute("current-area") { } - ~ReadServiceAreaCurrentLocation() + ~ReadServiceAreaCurrentArea() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::ServiceArea::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::ServiceArea::Attributes::CurrentLocation::Id; + constexpr chip::AttributeId attributeId = chip::app::Clusters::ServiceArea::Attributes::CurrentArea::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); __auto_type * cluster = [[MTRBaseClusterServiceArea alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - [cluster readAttributeCurrentLocationWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"ServiceArea.CurrentLocation response %@", [value description]); + [cluster readAttributeCurrentAreaWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { + NSLog(@"ServiceArea.CurrentArea response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { - LogNSError("ServiceArea CurrentLocation read Error", error); + LogNSError("ServiceArea CurrentArea read Error", error); RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); } SetCommandExitStatus(error); @@ -104292,21 +104292,21 @@ class ReadServiceAreaCurrentLocation : public ReadAttribute { } }; -class SubscribeAttributeServiceAreaCurrentLocation : public SubscribeAttribute { +class SubscribeAttributeServiceAreaCurrentArea : public SubscribeAttribute { public: - SubscribeAttributeServiceAreaCurrentLocation() - : SubscribeAttribute("current-location") + SubscribeAttributeServiceAreaCurrentArea() + : SubscribeAttribute("current-area") { } - ~SubscribeAttributeServiceAreaCurrentLocation() + ~SubscribeAttributeServiceAreaCurrentArea() { } CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::ServiceArea::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::ServiceArea::Attributes::CurrentLocation::Id; + constexpr chip::CommandId attributeId = chip::app::Clusters::ServiceArea::Attributes::CurrentArea::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); @@ -104321,10 +104321,10 @@ class SubscribeAttributeServiceAreaCurrentLocation : public SubscribeAttribute { if (mAutoResubscribe.HasValue()) { params.resubscribeAutomatically = mAutoResubscribe.Value(); } - [cluster subscribeAttributeCurrentLocationWithParams:params + [cluster subscribeAttributeCurrentAreaWithParams:params subscriptionEstablished:^() { mSubscriptionEstablished = YES; } reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"ServiceArea.CurrentLocation response %@", [value description]); + NSLog(@"ServiceArea.CurrentArea response %@", [value description]); if (error == nil) { RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); } else { @@ -196261,29 +196261,29 @@ void registerClusterServiceArea(Commands & commands) commands_list clusterCommands = { make_unique(Id), // #if MTR_ENABLE_PROVISIONAL - make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL make_unique(Id), // make_unique(Id), // make_unique(Id), // #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL make_unique(), // make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // + make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL make_unique(), // From 2a6f5e19eac1435ca8d29ef69a979dc821199f91 Mon Sep 17 00:00:00 2001 From: Marius Tache <102153746+marius-alex-tache@users.noreply.github.com> Date: Mon, 5 Aug 2024 17:15:00 +0300 Subject: [PATCH 09/41] [NXP][scripts] Fix smu2 target (#34771) Signed-off-by: marius-alex-tache --- scripts/build/build/targets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py index 433d98911f2f1f..827c7db045b825 100755 --- a/scripts/build/build/targets.py +++ b/scripts/build/build/targets.py @@ -521,7 +521,7 @@ def BuildNxpTarget(): target.AppendModifier(name="low-power", low_power=True).OnlyIfRe('contact-sensor') target.AppendModifier(name="lit", enable_lit=True).OnlyIfRe('contact-sensor') target.AppendModifier(name="fro32k", use_fro32k=True).OnlyIfRe('k32w0') - target.AppendModifier(name="smu2", smu2=True).OnlyIfRe('k32w1-lighting') + target.AppendModifier(name="smu2", smu2=True).OnlyIfRe('k32w1-freertos-lighting') target.AppendModifier(name="dac-conversion", convert_dac_pk=True).OnlyIfRe('factory').ExceptIfRe('(k32w0|rw61x)') target.AppendModifier(name="rotating-id", enable_rotating_id=True).ExceptIfRe('rw61x') target.AppendModifier(name="sw-v2", has_sw_version_2=True) From 814577ff372c52036aed8c5ab8fc6c6e6f4059bf Mon Sep 17 00:00:00 2001 From: Jakub Latusek Date: Mon, 5 Aug 2024 16:46:38 +0200 Subject: [PATCH 10/41] Update Build on Linux (fake, gcc_release, clang, simulated) image fix clang-tidy issues (#34404) * Fix clang-tidy issues * Update image version * Use c++ to manage files * Reverse changes in sockets impl --- .github/workflows/build.yaml | 2 +- .../CodegenDataModelProvider.cpp | 2 +- src/tools/spake2p/Cmd_GenVerifier.cpp | 83 +++++++++---------- 3 files changed, 43 insertions(+), 44 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 10f638a67de092..3ec8fd379c3fe7 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -138,7 +138,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: ghcr.io/project-chip/chip-build:54 + image: ghcr.io/project-chip/chip-build:65 volumes: - "/:/runner-root-volume" - "/tmp/log_output:/tmp/test_logs" diff --git a/src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp b/src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp index cea75c8d0c1ccc..312f175778a314 100644 --- a/src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp +++ b/src/app/codegen-data-model-provider/CodegenDataModelProvider.cpp @@ -284,7 +284,7 @@ std::optional CodegenDataModelProvider::TryFindEndpointIndex(EndpointI EndpointId CodegenDataModelProvider::NextEndpoint(EndpointId before) { - const unsigned lastEndpointIndex = emberAfEndpointCount(); + const uint16_t lastEndpointIndex = emberAfEndpointCount(); std::optional before_idx = TryFindEndpointIndex(before); if (!before_idx.has_value()) diff --git a/src/tools/spake2p/Cmd_GenVerifier.cpp b/src/tools/spake2p/Cmd_GenVerifier.cpp index dae873020b67fa..e5665501401359 100644 --- a/src/tools/spake2p/Cmd_GenVerifier.cpp +++ b/src/tools/spake2p/Cmd_GenVerifier.cpp @@ -25,8 +25,10 @@ #include "spake2p.h" -#include -#include +#include +#include +#include +#include #include #include @@ -157,30 +159,29 @@ uint8_t gSalt[BASE64_MAX_DECODED_LEN(BASE64_ENCODED_LEN(kSpake2p_Max_PBKDF_Salt_ uint8_t gSaltDecodedLen = 0; uint8_t gSaltLen = 0; const char * gOutFileName = nullptr; -FILE * gPinCodeFile = nullptr; +std::ifstream gPinCodeFile; static uint32_t GetNextPinCode() { - if (!gPinCodeFile) + if (!gPinCodeFile.is_open()) { return chip::kSetupPINCodeUndefinedValue; } - char * pinCodeStr = nullptr; - size_t readSize = 8; - uint32_t pinCode = chip::kSetupPINCodeUndefinedValue; - if (getline(&pinCodeStr, &readSize, gPinCodeFile) != -1) + std::string pinCodeStr; + uint32_t pinCode = chip::kSetupPINCodeUndefinedValue; + std::getline(gPinCodeFile, pinCodeStr); + if (!gPinCodeFile.fail()) { - if (readSize > 8) + if (pinCodeStr.length() > 8) { - pinCodeStr[8] = 0; + pinCodeStr = pinCodeStr.substr(0, 8); } - pinCode = static_cast(atoi(pinCodeStr)); + pinCode = static_cast(atoi(pinCodeStr.c_str())); if (!chip::SetupPayload::IsValidSetupPIN(pinCode)) { - fprintf(stderr, "The line %s in PIN codes file is invalid, using a random PIN code.\n", pinCodeStr); + std::cerr << "The line " << pinCodeStr << " in PIN codes file is invalid, using a random PIN code.\n"; pinCode = chip::kSetupPINCodeUndefinedValue; } - free(pinCodeStr); } return pinCode; } @@ -206,8 +207,8 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char break; case 'f': - gPinCodeFile = fopen(arg, "r"); - if (!gPinCodeFile) + gPinCodeFile.open(arg, std::ios::in); + if (gPinCodeFile.fail()) { PrintArgError("%s: Failed to open the PIN code file: %s\n", progName, arg); return false; @@ -235,7 +236,7 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char case 's': if (strlen(arg) > BASE64_ENCODED_LEN(kSpake2p_Max_PBKDF_Salt_Length)) { - fprintf(stderr, "%s: Salt parameter too long: %s\n", progName, arg); + std::cerr << progName << ": Salt parameter too long: " << arg << "\n"; return false; } @@ -245,13 +246,13 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char // Now double-check if the length is correct. if (gSaltDecodedLen > kSpake2p_Max_PBKDF_Salt_Length) { - fprintf(stderr, "%s: Salt parameter too long: %s\n", progName, arg); + std::cerr << progName << ": Salt parameter too long: " << arg << "\n"; return false; } if (gSaltDecodedLen < kSpake2p_Min_PBKDF_Salt_Length) { - fprintf(stderr, "%s: Salt parameter too short: %s\n", progName, arg); + std::cerr << progName << ": Salt parameter too short: " << arg << "\n"; return false; } @@ -273,8 +274,8 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char bool Cmd_GenVerifier(int argc, char * argv[]) { - FILE * outFile = nullptr; - + std::ofstream outFile; + std::ostream * outStream = &outFile; if (argc == 1) { gHelpOptions.PrintBriefUsage(stderr); @@ -282,22 +283,22 @@ bool Cmd_GenVerifier(int argc, char * argv[]) } bool res = ParseArgs(CMD_NAME, argc, argv, gCmdOptionSets); - VerifyOrReturnError(res, false); + VerifyOrReturnValue(res, false); if (gIterationCount == 0) { - fprintf(stderr, "Please specify the iteration-count parameter.\n"); + std::cerr << "Please specify the iteration-count parameter.\n"; return false; } if (gSaltDecodedLen == 0 && gSaltLen == 0) { - fprintf(stderr, "Please specify at least one of the 'salt' or 'salt-len' parameters.\n"); + std::cerr << "Please specify at least one of the 'salt' or 'salt-len' parameters.\n"; return false; } if (gSaltDecodedLen != 0 && gSaltLen != 0 && gSaltDecodedLen != gSaltLen) { - fprintf(stderr, "The specified 'salt-len' doesn't match the length of 'salt' parameter.\n"); + std::cerr << "The specified 'salt-len' doesn't match the length of 'salt' parameter.\n"; return false; } if (gSaltLen == 0) @@ -307,28 +308,27 @@ bool Cmd_GenVerifier(int argc, char * argv[]) if (gOutFileName == nullptr) { - fprintf(stderr, "Please specify the output file name, or - for stdout.\n"); + std::cerr << "Please specify the output file name, or - for stdout.\n"; return false; } if (strcmp(gOutFileName, "-") != 0) { - outFile = fopen(gOutFileName, "w+b"); - if (outFile == nullptr) + outFile.open(gOutFileName, std::ios::binary | std::ios::trunc); + if (!outFile.is_open()) { - fprintf(stderr, "Unable to create file %s\n%s\n", gOutFileName, strerror(errno)); + std::cerr << "Unable to create file " << gOutFileName << "\n" << strerror(errno) << "\n"; return false; } } else { - outFile = stdout; + outStream = &std::cout; } - - if (fprintf(outFile, "Index,PIN Code,Iteration Count,Salt,Verifier\n") < 0 || ferror(outFile)) + (*outStream) << "Index,PIN Code,Iteration Count,Salt,Verifier\n"; + if (outStream->fail()) { - fprintf(stderr, "Error writing to output file: %s\n", strerror(errno)); - return false; + std::cerr << "Error writing to output file: " << strerror(errno) << "\n"; } for (uint32_t i = 0; i < gCount; i++) @@ -339,7 +339,7 @@ bool Cmd_GenVerifier(int argc, char * argv[]) CHIP_ERROR err = chip::Crypto::DRBG_get_bytes(salt, gSaltLen); if (err != CHIP_NO_ERROR) { - fprintf(stderr, "DRBG_get_bytes() failed.\n"); + std::cerr << "DRBG_get_bytes() failed.\n"; return false; } } @@ -353,7 +353,7 @@ bool Cmd_GenVerifier(int argc, char * argv[]) (gPinCode == chip::kSetupPINCodeUndefinedValue), gPinCode); if (err != CHIP_NO_ERROR) { - fprintf(stderr, "GeneratePASEVerifier() failed.\n"); + std::cerr << "GeneratePASEVerifier() failed.\n"; return false; } @@ -362,7 +362,7 @@ bool Cmd_GenVerifier(int argc, char * argv[]) err = verifier.Serialize(serializedVerifierSpan); if (err != CHIP_NO_ERROR) { - fprintf(stderr, "Spake2pVerifier::Serialize() failed.\n"); + std::cerr << "Spake2pVerifier::Serialize() failed.\n"; return false; } @@ -374,9 +374,11 @@ bool Cmd_GenVerifier(int argc, char * argv[]) uint32_t verifierB64Len = chip::Base64Encode32(serializedVerifier, kSpake2p_VerifierSerialized_Length, verifierB64); verifierB64[verifierB64Len] = '\0'; - if (fprintf(outFile, "%d,%08d,%d,%s,%s\n", i, gPinCode, gIterationCount, saltB64, verifierB64) < 0 || ferror(outFile)) + (*outStream) << i << "," << std::setfill('0') << std::setw(8) << gPinCode << "," << gIterationCount << "," << saltB64 << "," + << verifierB64 << "\n"; + if (outStream->fail()) { - fprintf(stderr, "Error writing to output file: %s\n", strerror(errno)); + std::cerr << "Error writing to output file: " << strerror(errno) << "\n"; return false; } @@ -386,9 +388,6 @@ bool Cmd_GenVerifier(int argc, char * argv[]) gSaltDecodedLen = 0; } - if (gPinCodeFile) - { - fclose(gPinCodeFile); - } + gPinCodeFile.close(); return true; } From b5ff34757d4d7cd26a31761495aca205816f3aca Mon Sep 17 00:00:00 2001 From: Tennessee Carmel-Veilleux Date: Mon, 5 Aug 2024 11:11:44 -0400 Subject: [PATCH 11/41] Remove obsolete TC_OCC_XXX YAML files (#34756) - Tests were replaced by Python --- .../suites/certification/Test_TC_OCC_2_1.yaml | 180 ------------------ .../suites/certification/Test_TC_OCC_2_3.yaml | 55 ------ .../Test_TC_OCC_2_4_Simulated.yaml | 40 ---- .../suites/certification/Test_TC_OCC_3_1.yaml | 59 ------ 4 files changed, 334 deletions(-) delete mode 100644 src/app/tests/suites/certification/Test_TC_OCC_2_1.yaml delete mode 100644 src/app/tests/suites/certification/Test_TC_OCC_2_3.yaml delete mode 100644 src/app/tests/suites/certification/Test_TC_OCC_2_4_Simulated.yaml delete mode 100644 src/app/tests/suites/certification/Test_TC_OCC_3_1.yaml diff --git a/src/app/tests/suites/certification/Test_TC_OCC_2_1.yaml b/src/app/tests/suites/certification/Test_TC_OCC_2_1.yaml deleted file mode 100644 index fba27160989231..00000000000000 --- a/src/app/tests/suites/certification/Test_TC_OCC_2_1.yaml +++ /dev/null @@ -1,180 +0,0 @@ -# Copyright (c) 2021 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. - -name: 30.2.1. [TC-OCC-2.1] Attributes with server as DUT - -PICS: - - OCC.S - -config: - nodeId: 0x12344321 - cluster: "Occupancy Sensing" - endpoint: 1 - -tests: - - label: "Step 1: Commission DUT to TH" - cluster: "DelayCommands" - command: "WaitForCommissionee" - arguments: - values: - - name: "nodeId" - value: nodeId - - - label: "Step 2: TH reads from the DUT the (0x0000) Occupancy attribute" - PICS: OCC.S.A0000 - command: "readAttribute" - attribute: "Occupancy" - response: - constraints: - type: bitmap8 - minValue: 0 - maxValue: 1 - - - label: - "Step 3: TH reads from the DUT the (0x0001) OccupancySensorType - attribute" - PICS: OCC.S.A0001 - command: "readAttribute" - attribute: "OccupancySensorType" - response: - constraints: - type: enum8 - minValue: 0 - maxValue: 3 - - - label: - "Step 4:TH reads from the DUT the (0x0002) OccupancySensorTypeBitmap - attribute" - PICS: OCC.S.A0002 - command: "readAttribute" - attribute: "OccupancySensorTypeBitmap" - response: - constraints: - type: bitmap8 - minValue: 1 - maxValue: 7 - - - label: - "Step 5: TH reads from the DUT the (0x0010) - PIROccupiedToUnoccupiedDelay optional attribute, if PIR sensor" - PICS: OCC.S.A0010 - command: "readAttribute" - attribute: "PIROccupiedToUnoccupiedDelay" - response: - constraints: - type: int16u - minValue: 0 - maxValue: 65535 - - - label: - "Step 6: TH reads from the DUT the (0x0011) - PIRUnoccupiedToOccupiedDelay optional attribute, if PIR sensor" - PICS: OCC.S.A0011 - command: "readAttribute" - attribute: "PIRUnoccupiedToOccupiedDelay" - response: - constraints: - type: int16u - minValue: 0 - maxValue: 65535 - - - label: - "Step 7: TH reads from the DUT the (0x0012) - PIRUnoccupiedToOccupiedThreshold optional attribute, if PIR sensor" - PICS: OCC.S.A0012 - command: "readAttribute" - attribute: "PIRUnoccupiedToOccupiedThreshold" - response: - constraints: - type: int8u - minValue: 1 - maxValue: 254 - - - label: - "Step 8: TH reads from the DUT the (0x0020) - UltrasonicOccupiedToUnoccupiedDelay optional attribute, if ultrasonic - sensor" - PICS: OCC.S.A0020 - command: "readAttribute" - attribute: "UltrasonicOccupiedToUnoccupiedDelay" - response: - constraints: - type: int16u - minValue: 0 - maxValue: 65535 - - - label: - "Step 9: TH reads from the DUT the (0x0021) - UltrasonicUnoccupiedToOccupiedDelay optional attribute, if ultrasonic - sensor" - PICS: OCC.S.A0021 - command: "readAttribute" - attribute: "UltrasonicUnoccupiedToOccupiedDelay" - response: - constraints: - type: int16u - minValue: 0 - maxValue: 65535 - - - label: - "Step 10: TH reads from the DUT the (0x0022) - UltrasonicUnoccupiedToOccupiedThreshold optional attribute, if - ultrasonic sensor" - PICS: OCC.S.A0022 - command: "readAttribute" - attribute: "UltrasonicUnoccupiedToOccupiedThreshold" - response: - constraints: - type: int8u - minValue: 1 - maxValue: 254 - - - label: - "Step 11:TH reads from the DUT the (0x0030) - PhysicalContactOccupiedToUnoccupiedDelay optional attribute, if - Physical Contact sensor" - PICS: OCC.S.A0030 - command: "readAttribute" - attribute: "PhysicalContactOccupiedToUnoccupiedDelay" - response: - constraints: - type: int16u - minValue: 0 - maxValue: 65535 - - - label: - "Step 12: TH reads from the DUT the (0x0031) - PhysicalContactUnoccupiedToOccupiedDelay optional attribute, if - Physical Contact sensor" - PICS: OCC.S.A0031 - command: "readAttribute" - attribute: "PhysicalContactUnoccupiedToOccupiedDelay" - response: - constraints: - type: int16u - minValue: 0 - maxValue: 65535 - - - label: - "Step 13: TH reads from the DUT the (0x0032) - PhysicalContactUnoccupiedToOccupiedThreshold optional attribute, if - Physical Contact sensor" - PICS: OCC.S.A0032 - command: "readAttribute" - attribute: "PhysicalContactUnoccupiedToOccupiedThreshold" - response: - constraints: - type: int8u - minValue: 1 - maxValue: 254 diff --git a/src/app/tests/suites/certification/Test_TC_OCC_2_3.yaml b/src/app/tests/suites/certification/Test_TC_OCC_2_3.yaml deleted file mode 100644 index ae96e2e6309955..00000000000000 --- a/src/app/tests/suites/certification/Test_TC_OCC_2_3.yaml +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) 2021 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. -# Auto-generated scripts for harness use only, please review before automation. The endpoints and cluster names are currently set to default - -name: - 3.2.3. [TC-OCC-2.3] OccupancySensorTypeBitmap and OccupancySensorType - interdependency with server as DUT - -PICS: - - OCC.S - -config: - nodeId: 0x12344321 - cluster: "Occupancy Sensing" - endpoint: 1 - -tests: - - label: "Step 1: Commission DUT to TH" - cluster: "DelayCommands" - command: "WaitForCommissionee" - arguments: - values: - - name: "nodeId" - value: nodeId - - - label: "Step 2: TH reads OccupancySensorType attribute from DUT" - PICS: OCC.S.A0001 - command: "readAttribute" - attribute: "OccupancySensorType" - response: - constraints: - type: enum8 - minValue: 0 - maxValue: 3 - - - label: "Step 3: TH reads OccupancySensorTypeBitmap attribute from DUT" - PICS: OCC.S.A0002 - command: "readAttribute" - attribute: "OccupancySensorTypeBitmap" - response: - constraints: - type: bitmap8 - minValue: 1 - maxValue: 7 diff --git a/src/app/tests/suites/certification/Test_TC_OCC_2_4_Simulated.yaml b/src/app/tests/suites/certification/Test_TC_OCC_2_4_Simulated.yaml deleted file mode 100644 index 03d37bcd79bff2..00000000000000 --- a/src/app/tests/suites/certification/Test_TC_OCC_2_4_Simulated.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2021 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. - -name: - 28.3.2. [TC-OCC-2.4] OccupancySensorTypeBitmap and OccupancySensorType - interdependency with client as DUT - -PICS: - - OCC.C - -config: - nodeId: 0x12344321 - cluster: "Occupancy Sensing" - endpoint: 1 - -tests: - #- label: "Wait for the device to be commissioned" - # cluster: "DelayCommands" - # command: "WaitForCommissioning" - - - label: "TH reads OccupancySensorType attribute from DUT" - PICS: OCC.C.A0001 - wait: "readAttribute" - attribute: "OccupancySensorType" - - - label: "TH reads OccupancySensorTypeBitmap attribute from DUT" - PICS: OCC.C.A0002 - wait: "readAttribute" - attribute: "OccupancySensorTypeBitmap" diff --git a/src/app/tests/suites/certification/Test_TC_OCC_3_1.yaml b/src/app/tests/suites/certification/Test_TC_OCC_3_1.yaml deleted file mode 100644 index c246342b18a448..00000000000000 --- a/src/app/tests/suites/certification/Test_TC_OCC_3_1.yaml +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (c) 2021 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. - -name: 27.3.3. [TC-OCC-3.1] Primary functionality with server as DUT - -PICS: - - OCC.S - -config: - nodeId: 0x12344321 - cluster: "Occupancy Sensing" - endpoint: 1 - -tests: - - label: "Step 1: Commission DUT to TH" - cluster: "DelayCommands" - command: "WaitForCommissionee" - arguments: - values: - - name: "nodeId" - value: nodeId - - - label: "Step 2: TH reads Occupancy attribute from DUT" - PICS: OCC.S.A0000 - command: "readAttribute" - attribute: "Occupancy" - response: - saveAs: OccupancyValue - - - label: "Step 3: Operate on DUT to change the occupancy status" - cluster: "LogCommands" - command: "UserPrompt" - PICS: PICS_USER_PROMPT && OCC.M.OccupancyChange - arguments: - values: - - name: "message" - value: "Please enter 'y' for success" - - name: "expectedValue" - value: "y" - - - label: - "Step 4: after a few seconds, TH reads Occupancy attribute from DUT" - PICS: OCC.S.A0000 && OCC.M.OccupancyChange - command: "readAttribute" - attribute: "Occupancy" - response: - constraints: - notValue: OccupancyValue From b9c192b7cf8e7ffc697fa9b25eaeb6c5faa09365 Mon Sep 17 00:00:00 2001 From: Hasty Granbery Date: Mon, 5 Aug 2024 08:37:24 -0700 Subject: [PATCH 12/41] [HVAC] Use atomic writes with Presets (#34570) * Add support for Presets attributes and commands to the Thermostat cluster Clean up the Thermostat cluster and remove the TemperatureSetpointHoldPolicy attribute and SetTemperatureSetpointHoldPolicy command * Restyled by whitespace * Restyled by clang-format * Restyled by gn. * Fix build error for Linux configure build of all-clusters-app * Fix Darwin CI issues Editorial fixes * Restyled by clang-format * More fixes * Restyled by clang-format * BUILD.gn fixes for CI * Apply suggestions from code review Co-authored-by: Boris Zbarsky * Address review comments. * Restyled by clang-format * Regenerate Thermostat XML from spec * Move atomic enum to global-enums.xml, actually # Conflicts: # src/app/zap-templates/zcl/data-model/chip/global-structs.xml * Regenerate XML and convert thermostat-server to atomic writes * Pull in ACCapacityFormat typo un-fix * Update Test_TC_TSTAT_1_1 to know about AtomicResponse command. * Restyled patch * Fix weird merge with upstream * Fix emberAfIsTypeSigned not understanding temperature type * Merge fixes from atomic write branch * Relocate thermostat-manager sample code to all-clusters-common * Fix g++ build error on linux * Fix C formatter for long int, cast whole expression * Sync cast fix with master * Add thermostat-common dependency to thermostat app under linux * Remove MatterPostAttributeChangeCallback from thermostat-manager, as it conflicts with other implementations * Convert Atomic enums and structs to global * Restyled patch * Apply suggestions from code review Co-authored-by: Boris Zbarsky * Regen with alchemy 0.6.1 * Updates based on comments * Add TC_MCORE_FS_1_3.py test implementation (#34650) * Fix most TC-SWTCH-2.4 remaining issues (#34677) - Move 2.4 in a better place in the file - Add test steps properly - Allow default button press position override Issue #34656 Testing done: - Test still passes on DUT with automation * Initial test script for Fabric Sync TC_MCORE_FS_1_2 (#34675) * Initial test script for Fabric Sync TC_MCORE_FS_1_2 * Apply suggestions from code review Co-authored-by: C Freeman * Address Review Comments * Address review comments * Fix default timeout after other timeouts changed * Restyled by autopep8 * Fix linter error --------- Co-authored-by: C Freeman Co-authored-by: Restyled.io * Test automation for FabricSync ICD BridgedDeviceBasicInfoCluster (#34628) * WIP Bridged ICD, commissioning to both fabrics * wip testing sending KeepActive * wip most steps implemented * using SIGSTOP and SIGCONT to control ICD server pausing * Update src/python_testing/TC_BRBINFO_4_1.py Co-authored-by: Terence Hampson * comments addressed * more comments addressed * lint pass * Update src/python_testing/TC_BRBINFO_4_1.py Co-authored-by: C Freeman * comments addressed, incl TH_SERVER configurable * added setupQRCode and setupManualCode as options for DUT commissioning * Restyled by autopep8 * Restyled by isort * Update src/python_testing/TC_BRBINFO_4_1.py Co-authored-by: Terence Hampson * Update src/python_testing/TC_BRBINFO_4_1.py Co-authored-by: Terence Hampson * Update src/python_testing/TC_BRBINFO_4_1.py Co-authored-by: Terence Hampson * comments addressed * Restyled by autopep8 --------- Co-authored-by: Terence Hampson Co-authored-by: C Freeman Co-authored-by: Restyled.io * ServiceArea test scripts (#34548) * initial commit * fix bugs * fix issues reported by the linter * fix bug in checking for unique areaDesc * add TC 1.5 * Update src/python_testing/TC_SEAR_1_2.py Co-authored-by: William * Update src/python_testing/TC_SEAR_1_2.py Co-authored-by: William * address code review comments * fix issue introduced by the previous commit * address code review feedback * Update src/python_testing/TC_SEAR_1_2.py Co-authored-by: Kiel Oleson * address code review feedback * remove PICS checked by the TC_SEAR_1.6 * more code review updates * Restyled by autopep8 --------- Co-authored-by: William Co-authored-by: Kiel Oleson Co-authored-by: Restyled.io * Remove manual tests for Thermostat presets (#34679) * Dump details about leaked ExchangeContexts before aborting (#34617) * Dump details about leaked ExchangeContexts before aborting This is implemented via a VerifyOrDieWithObject() variant of the existing VerifyOrDie() macro that calls a DumpToLog() method on the provided object if it exists (otherwise this is simply a no-op). If CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE is not enabled, VerifyOrDieWithObject() simply behaves like a plain VerifyOrDie(). DumpToLog() implementations can use ChipLogFormatRtti to log type information about an object (usually a delegate); if RTTI is disabled this simply outputs whether the object was null or not. * Address review comments * Make gcc happy and improve documentation * Remove unused include * Fix compile error without CHIP_CONFIG_VERBOSE_VERIFY_OR_DIE * Avoid unused parameter warning * [TI] CC13x4_26x4 build fixes (#34682) * lwip pbuf, map file, and hex creation when OTA is disabled * added cc13x4 family define around the non OTA hex creation * whitespace fix * reversed custom factoy data flash with cc13x4 check * more whitespace fixes * [ICD] Add missing polling function to NoWifi connectivity manager (#34684) * Add missing polling function to NoWifi connectivity manager * Update GenericConnectivityManagerImpl_NoWiFi.h Co-authored-by: Boris Zbarsky --------- Co-authored-by: Boris Zbarsky * [OPSTATE] Add Q test script for CountdownTime (#34632) * Add Q test * Added test to test set * Remove unused var * Restyled by autopep8 * Restyled by isort * Fix name * Use pics over other method * Removed unused stuff * Added pipe commands * Fix reset * Get example to report appropriate changes. * WiP * Added some comments * Changes to make things work * Removed dev msgs * Missed some * Removed dev msgs * Straggler * Restyled by clang-format * Restyled by autopep8 * Restyled by isort * Commented unused var * Update examples/all-clusters-app/linux/AllClustersCommandDelegate.cpp * Fix bug --------- Co-authored-by: Restyled.io * YAML update to BRBINFO, ProductId (#34513) * Bridged Device Information Cluster, Attribute ProductID test reflects marking as O, not X * Update src/app/tests/suites/certification/Test_TC_BRBINFO_2_1.yaml Co-authored-by: Terence Hampson * corrected pics * corrected pics * WIP Bridged ICD, commissioning to both fabrics * wip testing sending KeepActive * update to bridged-device-basic-information.xml and zap generated files * removed unrelated file --------- Co-authored-by: Terence Hampson Co-authored-by: Andrei Litvin * Fix simplified Linux tv-casting-app gn build error. (#34692) * adding parallel execution to restyle-diff (#34663) * adding parallel execution to restyle-diff * using xargs to call restyle-paths * fixing Copyright year * restyle the restyler * Add some bits to exercise global structs/enums to Unit Testing cluster. (#34540) * Adds things to the Unit Testing cluster XML. * This requires those things to be enabled in all-clusters-app, all-clusters-minimal-app, and one of the chef contact sensors to pass CI. * That requires an implementation in test-cluster-server * At which point might as well add a YAML test to exercise it all. * [Silabs] Port platform specific Multi-Chip OTA work (#34440) * Pull request #1836: Cherry multi ota Merge in WMN_TOOLS/matter from cherry-multi-ota to silabs_slc_1.3 Squashed commit of the following: commit 4320bb46571658bc44fb82345348265def394991 Author: Michael Rupp Date: Fri May 10 14:26:07 2024 -0400 remove some unwanted diffs in provision files commit be160931dc600de7e7ead378b70d6a43c3945e46 Author: Michael Rupp Date: Fri May 10 14:24:25 2024 -0400 revert changes to generator.project.mak commit 14b6605887166e6d5284a61feb2bf407d850bdcf Author: Michael Rupp Date: Fri May 10 13:06:12 2024 -0400 revert NVM key changes and script changes ... and 8 more commits * Restyled by whitespace * Restyled by clang-format * Restyled by gn * Restyled by autopep8 * remove unused libs caught by linter * update doctree with new readmes * rerun CI, cirque failing for unknown reasons * fix include guards in provision examples * Restyled by clang-format --------- Co-authored-by: Restyled.io * Add python tests for Thermostat presets feature (#34693) * Add python tests for Thermostat presets feature * Restyled by autopep8 * Restyled by isort * Update the PICS code for presets attribute --------- Co-authored-by: Restyled.io * removing unneccessary git fetch (#34698) * Restyle patch * Regen to fix ordering of global structs * Apply suggestions from code review Co-authored-by: Boris Zbarsky * Return correct AtomicResponse when committing or rolling back * Patch tests for atomic write of presets * Fix tests to work with the new setup. Specific changes: * Enable SetActivePresetRequest command in all-clusters-app. * Fix assignment of a PresetStructWithOwnedMembers to another PresetStructWithOwnedMembers to actually work correctly. * Move constraint checks that happen on write from commit to write. * Fix sending of atomic responses to not have use-stack-after-return. * Fix PICS for the tests involved. * Fix PICS values for atomic requests * Remove PresetsSchedulesEditable and QueuedPreset from various places * Restyled patch * Restyled patch, again * Remove PICS value for PresetsSchedulesEditable * clang-tidy fixes * clang-tidy fixes --------- Co-authored-by: Nivedita Sarkar Co-authored-by: Restyled.io Co-authored-by: Nivi Sarkar <55898241+nivi-apple@users.noreply.github.com> Co-authored-by: Boris Zbarsky Co-authored-by: Terence Hampson Co-authored-by: Tennessee Carmel-Veilleux Co-authored-by: Chris Letnick Co-authored-by: C Freeman Co-authored-by: Douglas Rocha Ferraz Co-authored-by: Petru Lauric <81822411+plauric@users.noreply.github.com> Co-authored-by: William Co-authored-by: Kiel Oleson Co-authored-by: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Co-authored-by: Anu Biradar <104591549+abiradarti@users.noreply.github.com> Co-authored-by: mkardous-silabs <84793247+mkardous-silabs@users.noreply.github.com> Co-authored-by: Rob Bultman Co-authored-by: Andrei Litvin Co-authored-by: Shao Ling Tan <161761051+shaoltan-amazon@users.noreply.github.com> Co-authored-by: Amine Alami <43780877+Alami-Amine@users.noreply.github.com> Co-authored-by: Michael Rupp <95718139+mykrupp@users.noreply.github.com> --- .github/workflows/tests.yaml | 2 + .vscode/settings.json | 4 +- .../air-purifier-app.matter | 76 ++- .../air-quality-sensor-app.matter | 11 + .../all-clusters-app.matter | 89 ++- .../all-clusters-common/all-clusters-app.zap | 116 +++- .../all-clusters-minimal-app.matter | 76 ++- .../bridge-common/bridge-app.matter | 11 + ...p_rootnode_dimmablelight_bCwGYSDpoe.matter | 11 + .../rootnode_airpurifier_73a6fe2651.matter | 11 + ...umiditysensor_thermostat_56de3d5f45.matter | 76 ++- ...ootnode_airqualitysensor_e63187f6c9.matter | 11 + ...ootnode_basicvideoplayer_0ff86e943b.matter | 11 + ...de_colortemperaturelight_hbUnzYVeyn.matter | 11 + .../rootnode_contactsensor_27f76aeaf5.matter | 11 + .../rootnode_contactsensor_lFAGG1bfRO.matter | 11 + .../rootnode_dimmablelight_bCwGYSDpoe.matter | 11 + ...tnode_dimmablepluginunit_f8a9a0b9d4.matter | 11 + .../rootnode_dishwasher_cc105034fe.matter | 11 + .../rootnode_doorlock_aNKYAreMXE.matter | 11 + ...tnode_extendedcolorlight_8lcaaYJVAa.matter | 11 + .../devices/rootnode_fan_7N2TobIlOX.matter | 11 + .../rootnode_flowsensor_1zVxHedlaV.matter | 11 + .../rootnode_genericswitch_2dfff6e516.matter | 11 + .../rootnode_genericswitch_9866e35d0b.matter | 11 + ...tnode_heatingcoolingunit_ncdGai1E5a.matter | 76 ++- .../rootnode_humiditysensor_Xyj4gda6Hb.matter | 11 + .../rootnode_laundrywasher_fb10d238c8.matter | 11 + .../rootnode_lightsensor_lZQycTFcJK.matter | 11 + ...rootnode_occupancysensor_iHyVgifZuo.matter | 11 + .../rootnode_onofflight_bbs1b7IaOV.matter | 11 + .../rootnode_onofflight_samplemei.matter | 11 + ...ootnode_onofflightswitch_FsPlMr090Q.matter | 11 + ...rootnode_onoffpluginunit_Wtf8ss5EBY.matter | 11 + .../rootnode_pressuresensor_s0qC9wLH4k.matter | 11 + .../devices/rootnode_pump_5f904818cc.matter | 11 + .../devices/rootnode_pump_a811bb33a0.matter | 11 + ...eraturecontrolledcabinet_ffdb696680.matter | 11 + ...ode_roboticvacuumcleaner_1807ff0c49.matter | 11 + ...tnode_roomairconditioner_9cf3607804.matter | 76 ++- .../rootnode_smokecoalarm_686fe0dcb8.matter | 11 + .../rootnode_speaker_RpzeXdimqA.matter | 11 + ...otnode_temperaturesensor_Qy1zkNW7c3.matter | 11 + .../rootnode_thermostat_bm3fb8dhYi.matter | 76 ++- .../rootnode_windowcovering_RLCxaGi9Yx.matter | 11 + .../contact-sensor-app.matter | 11 + .../nxp/zap-lit/contact-sensor-app.matter | 11 + .../nxp/zap-sit/contact-sensor-app.matter | 11 + .../dishwasher-common/dishwasher-app.matter | 11 + .../energy-management-app.matter | 11 + .../fabric-bridge-app.matter | 11 + .../nxp/zap/laundry-washer-app.matter | 11 + .../light-switch-app.matter | 11 + .../light-switch-app/qpg/zap/switch.matter | 11 + .../data_model/lighting-app-ethernet.matter | 11 + .../data_model/lighting-app-thread.matter | 11 + .../data_model/lighting-app-wifi.matter | 11 + .../lighting-common/lighting-app.matter | 11 + .../nxp/zap/lighting-on-off.matter | 11 + examples/lighting-app/qpg/zap/light.matter | 11 + .../data_model/lighting-thread-app.matter | 11 + .../data_model/lighting-wifi-app.matter | 11 + .../lit-icd-common/lit-icd-server-app.matter | 11 + examples/lock-app/lock-common/lock-app.matter | 11 + examples/lock-app/nxp/zap/lock-app.matter | 11 + examples/lock-app/qpg/zap/lock.matter | 11 + .../log-source-common/log-source-app.matter | 11 + .../microwave-oven-app.matter | 11 + .../network-manager-app.matter | 11 + .../ota-provider-app.matter | 11 + .../ota-requestor-app.matter | 11 + .../placeholder/linux/apps/app1/config.matter | 141 +++-- .../placeholder/linux/apps/app2/config.matter | 141 +++-- examples/pump-app/pump-common/pump-app.matter | 11 + .../silabs/data_model/pump-thread-app.matter | 11 + .../silabs/data_model/pump-wifi-app.matter | 11 + .../pump-controller-app.matter | 11 + .../refrigerator-app.matter | 11 + examples/rvc-app/rvc-common/rvc-app.matter | 11 + .../smoke-co-alarm-app.matter | 11 + .../temperature-measurement.matter | 11 + .../linux/include/thermostat-delegate-impl.h | 2 + .../linux/thermostat-delegate-impl.cpp | 77 +-- .../thermostat/linux/thermostat-manager.cpp | 24 +- .../nxp/zap/thermostat_matter_thread.matter | 76 ++- .../nxp/zap/thermostat_matter_wifi.matter | 76 ++- .../qpg/zap/thermostaticRadiatorValve.matter | 76 ++- .../thermostat-common/thermostat.matter | 84 ++- .../thermostat-common/thermostat.zap | 36 +- examples/tv-app/tv-common/tv-app.matter | 11 + .../tv-casting-common/tv-casting-app.matter | 11 + .../virtual-device-app.matter | 11 + examples/window-app/common/window-app.matter | 11 + scripts/rules.matterlint | 2 + .../zap/tests/inputs/all-clusters-app.zap | 108 ++-- .../app-templates/IMClusterCommandHandler.cpp | 27 + .../all-clusters-app/app-templates/access.h | 3 + .../app-templates/endpoint_config.h | 153 ++--- .../PresetStructWithOwnedMembers.cpp | 13 +- .../PresetStructWithOwnedMembers.h | 3 +- .../thermostat-server/thermostat-delegate.h | 5 + .../thermostat-server/thermostat-server.cpp | 586 ++++++++++-------- .../thermostat-server/thermostat-server.h | 50 +- src/app/tests/suites/certification/PICS.yaml | 39 +- .../certification/Test_TC_TSTAT_1_1.yaml | 4 +- .../certification/Test_TC_TSTAT_4_1.yaml | 19 +- .../tests/suites/certification/ci-pics-values | 13 +- src/app/util/attribute-table.cpp | 3 +- src/app/zap-templates/zcl/data-model/all.xml | 2 + .../zcl/data-model/chip/global-bitmaps.xml | 36 ++ .../zcl/data-model/chip/global-enums.xml | 43 ++ .../zcl/data-model/chip/global-structs.xml | 18 +- .../data-model/chip/thermostat-cluster.xml | 236 ++++--- .../zcl/zcl-with-test-extensions.json | 2 + src/app/zap-templates/zcl/zcl.json | 2 + .../data_model/controller-clusters.matter | 76 ++- .../chip/devicecontroller/ChipClusters.java | 109 ++-- .../chip/devicecontroller/ChipStructs.java | 71 ++- .../devicecontroller/ClusterIDMapping.java | 15 +- .../devicecontroller/ClusterInfoMapping.java | 86 +-- .../devicecontroller/ClusterReadMapping.java | 11 - .../chip/devicecontroller/cluster/files.gni | 1 + ...ostatClusterAtomicAttributeStatusStruct.kt | 56 ++ .../ThermostatClusterScheduleStruct.kt | 13 +- .../cluster/clusters/ThermostatCluster.kt | 206 +++--- .../java/matter/controller/cluster/files.gni | 1 + ...ostatClusterAtomicAttributeStatusStruct.kt | 56 ++ .../ThermostatClusterScheduleStruct.kt | 13 +- .../CHIPAttributeTLVValueDecoder.cpp | 48 +- .../python/chip/clusters/CHIPClusters.py | 30 +- .../python/chip/clusters/Objects.py | 94 +-- .../python/chip/clusters/__init__.py | 4 +- .../CHIP/templates/availability.yaml | 1 - .../MTRAttributeSpecifiedCheck.mm | 3 - .../MTRAttributeTLVValueDecoder.mm | 25 +- .../CHIP/zap-generated/MTRBaseClusters.h | 52 +- .../CHIP/zap-generated/MTRBaseClusters.mm | 117 +--- .../CHIP/zap-generated/MTRClusterConstants.h | 8 +- .../CHIP/zap-generated/MTRClusterNames.mm | 4 - .../CHIP/zap-generated/MTRClusters.h | 10 +- .../CHIP/zap-generated/MTRClusters.mm | 77 +-- .../zap-generated/MTRCommandPayloadsObjc.h | 67 +- .../zap-generated/MTRCommandPayloadsObjc.mm | 225 +++---- .../MTRCommandPayloads_Internal.h | 12 +- .../CHIP/zap-generated/MTRStructsObjc.h | 6 + .../CHIP/zap-generated/MTRStructsObjc.mm | 30 + src/python_testing/TC_TSTAT_4_2.py | 202 +++--- .../zap-generated/attributes/Accessors.cpp | 109 ++-- .../zap-generated/attributes/Accessors.h | 42 +- .../app-common/zap-generated/callback.h | 18 +- .../zap-generated/cluster-enums-check.h | 15 +- .../app-common/zap-generated/cluster-enums.h | 23 +- .../zap-generated/cluster-objects.cpp | 105 +++- .../zap-generated/cluster-objects.h | 150 +++-- .../app-common/zap-generated/ids/Attributes.h | 6 +- .../app-common/zap-generated/ids/Commands.h | 16 +- .../zap-generated/cluster/Commands.h | 134 +--- .../cluster/ComplexArgumentParser.cpp | 40 +- .../cluster/ComplexArgumentParser.h | 5 + .../cluster/logging/DataModelLogger.cpp | 50 +- .../cluster/logging/DataModelLogger.h | 5 + .../zap-generated/cluster/Commands.h | 270 ++------ 162 files changed, 3646 insertions(+), 2641 deletions(-) create mode 100644 src/app/zap-templates/zcl/data-model/chip/global-bitmaps.xml create mode 100644 src/app/zap-templates/zcl/data-model/chip/global-enums.xml create mode 100644 src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThermostatClusterAtomicAttributeStatusStruct.kt create mode 100644 src/controller/java/generated/java/matter/controller/cluster/structs/ThermostatClusterAtomicAttributeStatusStruct.kt diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 996b8a6178a57c..70f40efc502234 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -91,6 +91,8 @@ jobs: --no-print \ --log-level info \ src/app/zap-templates/zcl/data-model/chip/global-attributes.xml \ + src/app/zap-templates/zcl/data-model/chip/global-bitmaps.xml \ + src/app/zap-templates/zcl/data-model/chip/global-enums.xml \ src/app/zap-templates/zcl/data-model/chip/global-structs.xml \ src/app/zap-templates/zcl/data-model/chip/semantic-tag-namespace-enums.xml \ src/app/zap-templates/zcl/data-model/chip/access-control-definitions.xml \ diff --git a/.vscode/settings.json b/.vscode/settings.json index a8b3dd631afe4f..33bdd5e9f63d6f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -134,7 +134,9 @@ "thread": "cpp", "variant": "cpp", "any": "cpp", - "future": "cpp" + "future": "cpp", + "list": "cpp", + "unordered_set": "cpp" }, // Configure paths or glob patterns to exclude from file watching. "files.watcherExclude": { diff --git a/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter b/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter index 51a9dc6a155f1b..c79eacc2037129 100644 --- a/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter +++ b/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -1520,7 +1531,7 @@ cluster ActivatedCarbonFilterMonitoring = 114 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -1566,7 +1577,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -1639,7 +1649,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -1649,6 +1658,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -1714,7 +1727,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -1746,23 +1759,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -1803,8 +1816,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -1844,28 +1856,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for controlling a fan in a heating/cooling system. */ diff --git a/examples/air-quality-sensor-app/air-quality-sensor-common/air-quality-sensor-app.matter b/examples/air-quality-sensor-app/air-quality-sensor-common/air-quality-sensor-app.matter index 443a5d95056da8..d7667f228ef2e0 100644 --- a/examples/air-quality-sensor-app/air-quality-sensor-common/air-quality-sensor-app.matter +++ b/examples/air-quality-sensor-app/air-quality-sensor-common/air-quality-sensor-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; 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 1c99735fc6d66d..795f470b88a6a8 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 @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -5357,7 +5368,7 @@ cluster PumpConfigurationAndControl = 512 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -5403,7 +5414,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -5476,7 +5486,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -5486,6 +5495,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -5551,7 +5564,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -5583,23 +5596,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -5640,8 +5653,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -5681,28 +5693,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for controlling a fan in a heating/cooling system. */ @@ -9035,10 +9051,15 @@ endpoint 1 { ram attribute controlSequenceOfOperation default = 0x04; ram attribute systemMode default = 0x01; callback attribute presetTypes; + callback attribute scheduleTypes; ram attribute numberOfPresets default = 0; + ram attribute numberOfSchedules default = 0; + ram attribute numberOfScheduleTransitionPerDay default = 0xFF; ram attribute activePresetHandle; + ram attribute activeScheduleHandle; callback attribute presets; - ram attribute presetsSchedulesEditable; + callback attribute schedules; + ram attribute setpointHoldExpiryTimestamp; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute eventList; @@ -9047,10 +9068,10 @@ endpoint 1 { ram attribute clusterRevision default = 6; handle command SetpointRaiseLower; + handle command SetActiveScheduleRequest; handle command SetActivePresetRequest; - handle command StartPresetsSchedulesEditRequest; - handle command CancelPresetsSchedulesEditRequest; - handle command CommitPresetsSchedulesRequest; + handle command AtomicResponse; + handle command AtomicRequest; } server cluster FanControl { diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index cde6889cd93f19..7d0a13ade18778 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -16395,32 +16395,32 @@ "isEnabled": 1 }, { - "name": "SetActivePresetRequest", - "code": 6, + "name": "SetActiveScheduleRequest", + "code": 5, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 }, { - "name": "StartPresetsSchedulesEditRequest", - "code": 7, + "name": "SetActivePresetRequest", + "code": 6, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 }, { - "name": "CancelPresetsSchedulesEditRequest", - "code": 8, + "name": "AtomicResponse", + "code": 253, "mfgCode": null, - "source": "client", - "isIncoming": 1, + "source": "server", + "isIncoming": 0, "isEnabled": 1 }, { - "name": "CommitPresetsSchedulesRequest", - "code": 9, + "name": "AtomicRequest", + "code": 254, "mfgCode": null, "source": "client", "isIncoming": 1, @@ -16529,7 +16529,7 @@ "code": 17, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -16545,7 +16545,7 @@ "code": 18, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -16561,7 +16561,7 @@ "code": 21, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -16577,7 +16577,7 @@ "code": 22, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -16593,7 +16593,7 @@ "code": 23, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -16609,7 +16609,7 @@ "code": 24, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -16684,6 +16684,22 @@ "maxInterval": 65534, "reportableChange": 0 }, + { + "name": "ScheduleTypes", + "code": 73, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "NumberOfPresets", "code": 74, @@ -16700,6 +16716,38 @@ "maxInterval": 65534, "reportableChange": 0 }, + { + "name": "NumberOfSchedules", + "code": 75, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NumberOfScheduleTransitionPerDay", + "code": 77, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0xFF", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "ActivePresetHandle", "code": 78, @@ -16716,6 +16764,22 @@ "maxInterval": 65534, "reportableChange": 0 }, + { + "name": "ActiveScheduleHandle", + "code": 79, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "Presets", "code": 80, @@ -16733,11 +16797,27 @@ "reportableChange": 0 }, { - "name": "PresetsSchedulesEditable", + "name": "Schedules", + "code": 81, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SetpointHoldExpiryTimestamp", "code": 82, "mfgCode": null, "side": "server", - "type": "boolean", + "type": "epoch_s", "included": 1, "storageOption": "RAM", "singleton": 0, 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 47093a5857a2ab..223b572d025cb0 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 @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -3794,7 +3805,7 @@ cluster PumpConfigurationAndControl = 512 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -3840,7 +3851,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -3913,7 +3923,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -3923,6 +3932,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -3988,7 +4001,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -4020,23 +4033,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -4077,8 +4090,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -4118,28 +4130,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for controlling a fan in a heating/cooling system. */ diff --git a/examples/bridge-app/bridge-common/bridge-app.matter b/examples/bridge-app/bridge-common/bridge-app.matter index ef70beb4fa8001..de25428864fbe4 100644 --- a/examples/bridge-app/bridge-common/bridge-app.matter +++ b/examples/bridge-app/bridge-common/bridge-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter b/examples/chef/devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter index 87b1f69b2601cc..40e5bb05b9bb08 100644 --- a/examples/chef/devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter +++ b/examples/chef/devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter b/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter index c9620818b035e2..47399bbe07fedf 100644 --- a/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter +++ b/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter b/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter index 7c84e33077f67a..159ab6e2a8b5b6 100644 --- a/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter +++ b/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -1443,7 +1454,7 @@ cluster ActivatedCarbonFilterMonitoring = 114 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -1489,7 +1500,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -1562,7 +1572,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -1572,6 +1581,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -1637,7 +1650,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -1669,23 +1682,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -1726,8 +1739,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -1767,28 +1779,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for controlling a fan in a heating/cooling system. */ diff --git a/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter b/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter index d5cd9f968e9cae..5c54416f886d68 100644 --- a/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter +++ b/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter index b0e6cb0dcb99f5..4a925bdf876f45 100644 --- a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter +++ b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter b/examples/chef/devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter index c09d170fcfb211..7ce3ee0dc39630 100644 --- a/examples/chef/devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter +++ b/examples/chef/devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter b/examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter index 752331d2934dde..66dd9f6c2cff51 100644 --- a/examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter +++ b/examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter b/examples/chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter index bd37aa7ee5435e..72ade2bfbabea7 100644 --- a/examples/chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter +++ b/examples/chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter b/examples/chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter index 2e3fc88091d900..424388a3bc3369 100644 --- a/examples/chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter +++ b/examples/chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter b/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter index 031b6365db2517..d0a9913df155a1 100644 --- a/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter +++ b/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_dishwasher_cc105034fe.matter b/examples/chef/devices/rootnode_dishwasher_cc105034fe.matter index be4001d1e49b03..4fe29a645d9e6e 100644 --- a/examples/chef/devices/rootnode_dishwasher_cc105034fe.matter +++ b/examples/chef/devices/rootnode_dishwasher_cc105034fe.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter b/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter index a8233afe90b6c4..90292d1ea06c4e 100644 --- a/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter +++ b/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter b/examples/chef/devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter index 27473072e657c0..d4cea1c3c63b8c 100644 --- a/examples/chef/devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter +++ b/examples/chef/devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter b/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter index 1cb3ba2c5a63a8..7ea73610feaa7b 100644 --- a/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter +++ b/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter b/examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter index 8b4d4046f3b36f..ad880498571bc0 100644 --- a/examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter +++ b/examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter b/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter index 07a8e8ee7de63b..100ee17a1b84c7 100644 --- a/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter +++ b/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter b/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter index 204c7b2d7abf43..979b8046ce7901 100644 --- a/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter +++ b/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter index 208ddcea79b1bf..6ec3535eae0302 100644 --- a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter +++ b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -1800,7 +1811,7 @@ cluster FixedLabel = 64 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -1846,7 +1857,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -1919,7 +1929,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -1929,6 +1938,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -1994,7 +2007,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -2026,23 +2039,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -2083,8 +2096,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -2124,28 +2136,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for controlling a fan in a heating/cooling system. */ diff --git a/examples/chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter b/examples/chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter index 1aca96ae1e7824..1918e417c2b725 100644 --- a/examples/chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter +++ b/examples/chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_laundrywasher_fb10d238c8.matter b/examples/chef/devices/rootnode_laundrywasher_fb10d238c8.matter index 5be2b0c409d982..e327a8eb68ae75 100644 --- a/examples/chef/devices/rootnode_laundrywasher_fb10d238c8.matter +++ b/examples/chef/devices/rootnode_laundrywasher_fb10d238c8.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter b/examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter index aab7ae74ee127b..c801a97df380ee 100644 --- a/examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter +++ b/examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter b/examples/chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter index 3babdb7f9a57d0..0a9039409289e1 100644 --- a/examples/chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter +++ b/examples/chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter b/examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter index e58601388e94bd..05bd1e0dc4552d 100644 --- a/examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter +++ b/examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_onofflight_samplemei.matter b/examples/chef/devices/rootnode_onofflight_samplemei.matter index 65a0c490f23a0d..dfd0b1a07bf478 100644 --- a/examples/chef/devices/rootnode_onofflight_samplemei.matter +++ b/examples/chef/devices/rootnode_onofflight_samplemei.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter b/examples/chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter index 88462157a1c691..e6b65b5f357f8a 100644 --- a/examples/chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter +++ b/examples/chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter b/examples/chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter index 7f7d67cedfdf1c..95e0efdc1ce319 100644 --- a/examples/chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter +++ b/examples/chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter b/examples/chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter index 92f14706269c2d..b447bcaf9fd30d 100644 --- a/examples/chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter +++ b/examples/chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_pump_5f904818cc.matter b/examples/chef/devices/rootnode_pump_5f904818cc.matter index bd34fc60d32c57..905099c03e2b8d 100644 --- a/examples/chef/devices/rootnode_pump_5f904818cc.matter +++ b/examples/chef/devices/rootnode_pump_5f904818cc.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_pump_a811bb33a0.matter b/examples/chef/devices/rootnode_pump_a811bb33a0.matter index bc1c5228dade49..9e13f678310b78 100644 --- a/examples/chef/devices/rootnode_pump_a811bb33a0.matter +++ b/examples/chef/devices/rootnode_pump_a811bb33a0.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_refrigerator_temperaturecontrolledcabinet_temperaturecontrolledcabinet_ffdb696680.matter b/examples/chef/devices/rootnode_refrigerator_temperaturecontrolledcabinet_temperaturecontrolledcabinet_ffdb696680.matter index f68d7bf2aaefb0..b2e81d6229586e 100644 --- a/examples/chef/devices/rootnode_refrigerator_temperaturecontrolledcabinet_temperaturecontrolledcabinet_ffdb696680.matter +++ b/examples/chef/devices/rootnode_refrigerator_temperaturecontrolledcabinet_temperaturecontrolledcabinet_ffdb696680.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter b/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter index 6f88dc303da772..3b08c19cf02ed2 100644 --- a/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter +++ b/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter b/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter index d6e843c5937189..b01b11f56f8c58 100644 --- a/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter +++ b/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -1383,7 +1394,7 @@ cluster GroupKeyManagement = 63 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -1429,7 +1440,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -1502,7 +1512,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -1512,6 +1521,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -1577,7 +1590,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -1609,23 +1622,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -1666,8 +1679,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -1707,28 +1719,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for controlling a fan in a heating/cooling system. */ diff --git a/examples/chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter b/examples/chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter index 9354126302295d..8be645e41ddfea 100644 --- a/examples/chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter +++ b/examples/chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter b/examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter index bdad38f829a821..400606024bbb02 100644 --- a/examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter +++ b/examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter b/examples/chef/devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter index cb7eaa21e153a2..3132bdb15686b3 100644 --- a/examples/chef/devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter +++ b/examples/chef/devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter index 094673005fd5d2..751529c70dbb5c 100644 --- a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter +++ b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -1603,7 +1614,7 @@ cluster FixedLabel = 64 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -1649,7 +1660,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -1722,7 +1732,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -1732,6 +1741,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -1797,7 +1810,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -1829,23 +1842,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -1886,8 +1899,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -1927,28 +1939,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for controlling a fan in a heating/cooling system. */ diff --git a/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter b/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter index 737c351984bb64..3851f1d0328f32 100644 --- a/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter +++ b/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/contact-sensor-app/contact-sensor-common/contact-sensor-app.matter b/examples/contact-sensor-app/contact-sensor-common/contact-sensor-app.matter index 532fc6fff1531c..ee218d61684d4b 100644 --- a/examples/contact-sensor-app/contact-sensor-common/contact-sensor-app.matter +++ b/examples/contact-sensor-app/contact-sensor-common/contact-sensor-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter b/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter index fb2cf8f8289734..44bf8425d7a88a 100644 --- a/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter +++ b/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter b/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter index 21f793caedee04..cf2bee67f6da02 100644 --- a/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter +++ b/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/dishwasher-app/dishwasher-common/dishwasher-app.matter b/examples/dishwasher-app/dishwasher-common/dishwasher-app.matter index e5027342d1edb2..df35f214119b69 100644 --- a/examples/dishwasher-app/dishwasher-common/dishwasher-app.matter +++ b/examples/dishwasher-app/dishwasher-common/dishwasher-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.matter b/examples/energy-management-app/energy-management-common/energy-management-app.matter index 2b081f13a3827e..22b17a3b7dd58c 100644 --- a/examples/energy-management-app/energy-management-common/energy-management-app.matter +++ b/examples/energy-management-app/energy-management-common/energy-management-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter b/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter index 33e1d992b677b1..9294f0f069c57d 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter +++ b/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter b/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter index b204bae6345a2d..b993fe9100e101 100644 --- a/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter +++ b/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.matter b/examples/light-switch-app/light-switch-common/light-switch-app.matter index 1f2c3728b3098d..d9aa1313f34c0b 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.matter +++ b/examples/light-switch-app/light-switch-common/light-switch-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/light-switch-app/qpg/zap/switch.matter b/examples/light-switch-app/qpg/zap/switch.matter index a8a28edb2fbcf0..002943282c94bd 100644 --- a/examples/light-switch-app/qpg/zap/switch.matter +++ b/examples/light-switch-app/qpg/zap/switch.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/lighting-app/bouffalolab/data_model/lighting-app-ethernet.matter b/examples/lighting-app/bouffalolab/data_model/lighting-app-ethernet.matter index f60a0c186bda97..010ba4d1dc88a8 100644 --- a/examples/lighting-app/bouffalolab/data_model/lighting-app-ethernet.matter +++ b/examples/lighting-app/bouffalolab/data_model/lighting-app-ethernet.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/lighting-app/bouffalolab/data_model/lighting-app-thread.matter b/examples/lighting-app/bouffalolab/data_model/lighting-app-thread.matter index eddf3d467b282c..ae6ed8acaef557 100644 --- a/examples/lighting-app/bouffalolab/data_model/lighting-app-thread.matter +++ b/examples/lighting-app/bouffalolab/data_model/lighting-app-thread.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/lighting-app/bouffalolab/data_model/lighting-app-wifi.matter b/examples/lighting-app/bouffalolab/data_model/lighting-app-wifi.matter index b65db2f043639c..49f5f4f007adc9 100644 --- a/examples/lighting-app/bouffalolab/data_model/lighting-app-wifi.matter +++ b/examples/lighting-app/bouffalolab/data_model/lighting-app-wifi.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/lighting-app/lighting-common/lighting-app.matter b/examples/lighting-app/lighting-common/lighting-app.matter index 063304d69a222c..48650af7462729 100644 --- a/examples/lighting-app/lighting-common/lighting-app.matter +++ b/examples/lighting-app/lighting-common/lighting-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/lighting-app/nxp/zap/lighting-on-off.matter b/examples/lighting-app/nxp/zap/lighting-on-off.matter index d4e0e18bc3e985..4da56bd6ddff25 100644 --- a/examples/lighting-app/nxp/zap/lighting-on-off.matter +++ b/examples/lighting-app/nxp/zap/lighting-on-off.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/lighting-app/qpg/zap/light.matter b/examples/lighting-app/qpg/zap/light.matter index 652c45f6d83c71..b27ac3d90820da 100644 --- a/examples/lighting-app/qpg/zap/light.matter +++ b/examples/lighting-app/qpg/zap/light.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/lighting-app/silabs/data_model/lighting-thread-app.matter b/examples/lighting-app/silabs/data_model/lighting-thread-app.matter index b7d967d3c5ef0e..473d0c1efd44b9 100644 --- a/examples/lighting-app/silabs/data_model/lighting-thread-app.matter +++ b/examples/lighting-app/silabs/data_model/lighting-thread-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter b/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter index b1cd1c94be474a..38091dbe0ccbe0 100644 --- a/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter +++ b/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter index f4c9fa01731c7c..5d2ede841e2fcd 100644 --- a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter +++ b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/lock-app/lock-common/lock-app.matter b/examples/lock-app/lock-common/lock-app.matter index 50c416a2a937cf..aca989e2c43440 100644 --- a/examples/lock-app/lock-common/lock-app.matter +++ b/examples/lock-app/lock-common/lock-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/lock-app/nxp/zap/lock-app.matter b/examples/lock-app/nxp/zap/lock-app.matter index a8d2d9fd5eb230..528412e523b0a0 100644 --- a/examples/lock-app/nxp/zap/lock-app.matter +++ b/examples/lock-app/nxp/zap/lock-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/lock-app/qpg/zap/lock.matter b/examples/lock-app/qpg/zap/lock.matter index d3f76e4f719b5e..b38d2b96b27509 100644 --- a/examples/lock-app/qpg/zap/lock.matter +++ b/examples/lock-app/qpg/zap/lock.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/log-source-app/log-source-common/log-source-app.matter b/examples/log-source-app/log-source-common/log-source-app.matter index 38e6f51ee4d1de..c9af17203111cf 100644 --- a/examples/log-source-app/log-source-common/log-source-app.matter +++ b/examples/log-source-app/log-source-common/log-source-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** The Access Control Cluster exposes a data model view of a Node's Access Control List (ACL), which codifies the rules used to manage and enforce Access Control for the Node's endpoints and their associated diff --git a/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter b/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter index 36df5a7a835c5f..4c36a56025829e 100644 --- a/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter +++ b/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/network-manager-app/network-manager-common/network-manager-app.matter b/examples/network-manager-app/network-manager-common/network-manager-app.matter index 173b2a2c923601..89200240662d70 100644 --- a/examples/network-manager-app/network-manager-common/network-manager-app.matter +++ b/examples/network-manager-app/network-manager-common/network-manager-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter b/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter index 8b290cc5796e1a..6746a5ba516104 100644 --- a/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter +++ b/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */ cluster Descriptor = 29 { revision 2; diff --git a/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter b/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter index eb1703c55b85b1..da22094fd2e8c3 100644 --- a/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter +++ b/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/placeholder/linux/apps/app1/config.matter b/examples/placeholder/linux/apps/app1/config.matter index b4e96362bbb7c4..83d5c9745f5e9a 100644 --- a/examples/placeholder/linux/apps/app1/config.matter +++ b/examples/placeholder/linux/apps/app1/config.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -5078,7 +5089,7 @@ cluster PumpConfigurationAndControl = 512 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -5124,7 +5135,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -5197,7 +5207,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -5207,6 +5216,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -5272,7 +5285,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -5304,23 +5317,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -5361,8 +5374,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -5402,33 +5414,37 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; + } + + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -5474,7 +5490,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -5547,7 +5562,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -5557,6 +5571,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -5622,7 +5640,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -5654,23 +5672,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -5711,8 +5729,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -5752,28 +5769,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for configuring the user interface of a thermostat (which may be remote from the thermostat). */ diff --git a/examples/placeholder/linux/apps/app2/config.matter b/examples/placeholder/linux/apps/app2/config.matter index 65d42505d62e5c..00b620e45fa55b 100644 --- a/examples/placeholder/linux/apps/app2/config.matter +++ b/examples/placeholder/linux/apps/app2/config.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -5035,7 +5046,7 @@ cluster PumpConfigurationAndControl = 512 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -5081,7 +5092,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -5154,7 +5164,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -5164,6 +5173,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -5229,7 +5242,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -5261,23 +5274,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -5318,8 +5331,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -5359,33 +5371,37 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; + } + + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -5431,7 +5447,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -5504,7 +5519,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -5514,6 +5528,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -5579,7 +5597,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -5611,23 +5629,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -5668,8 +5686,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -5709,28 +5726,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for configuring the user interface of a thermostat (which may be remote from the thermostat). */ diff --git a/examples/pump-app/pump-common/pump-app.matter b/examples/pump-app/pump-common/pump-app.matter index ca2ba887cfaeee..4482329a1245e4 100644 --- a/examples/pump-app/pump-common/pump-app.matter +++ b/examples/pump-app/pump-common/pump-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/pump-app/silabs/data_model/pump-thread-app.matter b/examples/pump-app/silabs/data_model/pump-thread-app.matter index 15daa818e304a3..ec9b0e09f0318d 100644 --- a/examples/pump-app/silabs/data_model/pump-thread-app.matter +++ b/examples/pump-app/silabs/data_model/pump-thread-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/pump-app/silabs/data_model/pump-wifi-app.matter b/examples/pump-app/silabs/data_model/pump-wifi-app.matter index 15daa818e304a3..ec9b0e09f0318d 100644 --- a/examples/pump-app/silabs/data_model/pump-wifi-app.matter +++ b/examples/pump-app/silabs/data_model/pump-wifi-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter b/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter index 8f5ae594b044f4..74c2fbd6ca67ff 100644 --- a/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter +++ b/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/refrigerator-app/refrigerator-common/refrigerator-app.matter b/examples/refrigerator-app/refrigerator-common/refrigerator-app.matter index 3208239c974fa1..73036faa89b9da 100644 --- a/examples/refrigerator-app/refrigerator-common/refrigerator-app.matter +++ b/examples/refrigerator-app/refrigerator-common/refrigerator-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */ cluster Descriptor = 29 { revision 2; diff --git a/examples/rvc-app/rvc-common/rvc-app.matter b/examples/rvc-app/rvc-common/rvc-app.matter index 7983c155e279e6..8342817b1321e9 100644 --- a/examples/rvc-app/rvc-common/rvc-app.matter +++ b/examples/rvc-app/rvc-common/rvc-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter b/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter index cb192d1fa9ff1c..71aa847401e521 100644 --- a/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter +++ b/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter b/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter index c755a48de0f189..3b41b5a099ac0f 100644 --- a/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter +++ b/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */ cluster Descriptor = 29 { revision 2; diff --git a/examples/thermostat/linux/include/thermostat-delegate-impl.h b/examples/thermostat/linux/include/thermostat-delegate-impl.h index c4daef5fde1d6a..f559977f341949 100644 --- a/examples/thermostat/linux/include/thermostat-delegate-impl.h +++ b/examples/thermostat/linux/include/thermostat-delegate-impl.h @@ -54,6 +54,8 @@ class ThermostatDelegate : public Delegate CHIP_ERROR SetActivePresetHandle(const DataModel::Nullable & newActivePresetHandle) override; + void InitializePendingPresets() override; + CHIP_ERROR AppendToPendingPresetList(const Structs::PresetStruct::Type & preset) override; CHIP_ERROR GetPendingPresetAtIndex(size_t index, PresetStructWithOwnedMembers & preset) override; diff --git a/examples/thermostat/linux/thermostat-delegate-impl.cpp b/examples/thermostat/linux/thermostat-delegate-impl.cpp index 491e44a311c3e8..61d496f233b408 100644 --- a/examples/thermostat/linux/thermostat-delegate-impl.cpp +++ b/examples/thermostat/linux/thermostat-delegate-impl.cpp @@ -16,7 +16,8 @@ * limitations under the License. */ -#include "include/thermostat-delegate-impl.h" +#include +#include #include #include @@ -29,24 +30,6 @@ using namespace chip::app::Clusters::Thermostat::Structs; ThermostatDelegate ThermostatDelegate::sInstance; -namespace { - -/** - * @brief Checks if the presets are matching i.e the presetHandles are the same. - * - * @param[in] preset The preset to check. - * @param[in] presetToMatch The preset to match with. - * - * @return true If the presets match, false otherwise. If both preset handles are null, returns false - */ -bool PresetHandlesExistAndMatch(const PresetStructWithOwnedMembers & preset, const PresetStructWithOwnedMembers & presetToMatch) -{ - return !preset.GetPresetHandle().IsNull() && !presetToMatch.GetPresetHandle().IsNull() && - preset.GetPresetHandle().Value().data_equal(presetToMatch.GetPresetHandle().Value()); -} - -} // anonymous namespace - ThermostatDelegate::ThermostatDelegate() { mNumberOfPresets = kMaxNumberOfPresetTypes * kMaxNumberOfPresetsOfEachType; @@ -165,16 +148,29 @@ CHIP_ERROR ThermostatDelegate::SetActivePresetHandle(const DataModel::Nullable(preset.presetScenario) }; + mPendingPresets[mNextFreeIndexInPendingPresetsList].SetPresetHandle(DataModel::MakeNullable(ByteSpan(handle))); + } mNextFreeIndexInPendingPresetsList++; return CHIP_NO_ERROR; } @@ -193,37 +189,12 @@ CHIP_ERROR ThermostatDelegate::GetPendingPresetAtIndex(size_t index, PresetStruc CHIP_ERROR ThermostatDelegate::ApplyPendingPresets() { - - // TODO: #34546 - Need to support deletion of presets that are removed from Presets. + mNextFreeIndexInPresetsList = 0; for (uint8_t indexInPendingPresets = 0; indexInPendingPresets < mNextFreeIndexInPendingPresetsList; indexInPendingPresets++) { const PresetStructWithOwnedMembers & pendingPreset = mPendingPresets[indexInPendingPresets]; - - bool found = false; - for (uint8_t indexInPresets = 0; indexInPresets < mNextFreeIndexInPresetsList; indexInPresets++) - { - if (PresetHandlesExistAndMatch(mPresets[indexInPresets], pendingPreset)) - { - found = true; - - // Replace the preset with the pending preset - mPresets[indexInPresets] = pendingPreset; - } - } - - // If pending preset was not found in the Presets list, append to the Presets list. - if (!found) - { - - mPresets[mNextFreeIndexInPresetsList] = pendingPreset; - - // TODO: #34556 Since we support only one preset of each type, using the octet string containing the preset scenario - // suffices as the unique preset handle. Need to fix this to actually provide unique handles once multiple presets of - // each type are supported. - const uint8_t handle[] = { static_cast(pendingPreset.GetPresetScenario()) }; - mPresets[mNextFreeIndexInPresetsList].SetPresetHandle(DataModel::MakeNullable(ByteSpan(handle))); - mNextFreeIndexInPresetsList++; - } + mPresets[mNextFreeIndexInPresetsList] = pendingPreset; + mNextFreeIndexInPresetsList++; } return CHIP_NO_ERROR; } diff --git a/examples/thermostat/linux/thermostat-manager.cpp b/examples/thermostat/linux/thermostat-manager.cpp index e96f04a78d49e9..90d4588a131ca6 100644 --- a/examples/thermostat/linux/thermostat-manager.cpp +++ b/examples/thermostat/linux/thermostat-manager.cpp @@ -20,8 +20,8 @@ * Includes *********************************************************/ -#include "include/thermostat-manager.h" -#include "include/thermostat-delegate-impl.h" +#include +#include #include #include @@ -274,7 +274,7 @@ void ThermostatManager::ThermostatClusterAttributeChangeHandler(AttributeId attr break; default: { - ChipLogError(AppServer, "Unhandled thermostat attribute %x", attributeId); + ChipLogError(AppServer, "Unhandled thermostat attribute %u", static_cast(attributeId)); return; } break; @@ -490,25 +490,13 @@ static const char * RunningModeString(ThermostatRunningModeEnum runningMode) } } -void MatterPostAttributeChangeCallback(const ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, uint8_t * value) -{ - ClusterId clusterId = attributePath.mClusterId; - AttributeId attributeId = attributePath.mAttributeId; - ChipLogProgress(AppServer, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId)); - - ChipLogProgress(AppServer, - "Attribute ID changed: " ChipLogFormatMEI " Endpoint: %d ClusterId: " ChipLogFormatMEI - " Type: %u Value: %u, length %u", - ChipLogValueMEI(attributeId), attributePath.mEndpointId, ChipLogValueMEI(clusterId), type, *value, size); - - ThermostatMgr().AttributeChangeHandler(attributePath.mEndpointId, clusterId, attributeId, value, size); -} - void emberAfThermostatClusterInitCallback(EndpointId endpoint) { + ChipLogProgress(Zcl, "Starting Thermostat Manager"); + ThermostatManager().Init(); + // Register the delegate for the Thermostat auto & delegate = ThermostatDelegate::GetInstance(); - // Set the default delegate for endpoint kThermostatEndpoint. VerifyOrDie(endpoint == kThermostatEndpoint); SetDefaultDelegate(endpoint, &delegate); diff --git a/examples/thermostat/nxp/zap/thermostat_matter_thread.matter b/examples/thermostat/nxp/zap/thermostat_matter_thread.matter index 7b115dff3c7889..b85de2986ffd44 100644 --- a/examples/thermostat/nxp/zap/thermostat_matter_thread.matter +++ b/examples/thermostat/nxp/zap/thermostat_matter_thread.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -2194,7 +2205,7 @@ provisional cluster ScenesManagement = 98 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -2240,7 +2251,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -2313,7 +2323,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -2323,6 +2332,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -2388,7 +2401,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -2420,23 +2433,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -2477,8 +2490,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -2518,28 +2530,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } endpoint 0 { diff --git a/examples/thermostat/nxp/zap/thermostat_matter_wifi.matter b/examples/thermostat/nxp/zap/thermostat_matter_wifi.matter index 2c4aaa2b37cd0a..1cdce376d85543 100644 --- a/examples/thermostat/nxp/zap/thermostat_matter_wifi.matter +++ b/examples/thermostat/nxp/zap/thermostat_matter_wifi.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -2105,7 +2116,7 @@ provisional cluster ScenesManagement = 98 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -2151,7 +2162,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -2224,7 +2234,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -2234,6 +2243,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -2299,7 +2312,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -2331,23 +2344,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -2388,8 +2401,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -2429,28 +2441,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } endpoint 0 { diff --git a/examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter b/examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter index 9b7760d25744d2..8da05509bed572 100644 --- a/examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter +++ b/examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -1802,7 +1813,7 @@ cluster UserLabel = 65 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -1848,7 +1859,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -1921,7 +1931,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -1931,6 +1940,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -1996,7 +2009,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -2028,23 +2041,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -2085,8 +2098,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -2126,28 +2138,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for configuring the user interface of a thermostat (which may be remote from the thermostat). */ diff --git a/examples/thermostat/thermostat-common/thermostat.matter b/examples/thermostat/thermostat-common/thermostat.matter index 1b8698f61b894b..dc4b0a886108ab 100644 --- a/examples/thermostat/thermostat-common/thermostat.matter +++ b/examples/thermostat/thermostat-common/thermostat.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -1982,7 +1993,7 @@ cluster UserLabel = 65 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -2028,7 +2039,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -2101,7 +2111,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -2111,6 +2120,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -2176,7 +2189,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -2208,23 +2221,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -2265,8 +2278,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -2306,28 +2318,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for configuring the user interface of a thermostat (which may be remote from the thermostat). */ @@ -2777,7 +2793,7 @@ endpoint 1 { ram attribute numberOfPresets default = 0; ram attribute activePresetHandle; callback attribute presets; - ram attribute presetsSchedulesEditable; + ram attribute setpointHoldExpiryTimestamp; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute attributeList; @@ -2785,10 +2801,10 @@ endpoint 1 { ram attribute clusterRevision default = 6; handle command SetpointRaiseLower; + handle command SetActiveScheduleRequest; handle command SetActivePresetRequest; - handle command StartPresetsSchedulesEditRequest; - handle command CancelPresetsSchedulesEditRequest; - handle command CommitPresetsSchedulesRequest; + handle command AtomicResponse; + handle command AtomicRequest; } server cluster ThermostatUserInterfaceConfiguration { diff --git a/examples/thermostat/thermostat-common/thermostat.zap b/examples/thermostat/thermostat-common/thermostat.zap index e907730ee80696..8b2fe4f5c82318 100644 --- a/examples/thermostat/thermostat-common/thermostat.zap +++ b/examples/thermostat/thermostat-common/thermostat.zap @@ -4661,32 +4661,32 @@ "isEnabled": 1 }, { - "name": "SetActivePresetRequest", - "code": 6, + "name": "SetActiveScheduleRequest", + "code": 5, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 }, { - "name": "StartPresetsSchedulesEditRequest", - "code": 7, + "name": "SetActivePresetRequest", + "code": 6, "mfgCode": null, "source": "client", "isIncoming": 1, "isEnabled": 1 }, { - "name": "CancelPresetsSchedulesEditRequest", - "code": 8, + "name": "AtomicResponse", + "code": 253, "mfgCode": null, - "source": "client", - "isIncoming": 1, + "source": "server", + "isIncoming": 0, "isEnabled": 1 }, { - "name": "CommitPresetsSchedulesRequest", - "code": 9, + "name": "AtomicRequest", + "code": 254, "mfgCode": null, "source": "client", "isIncoming": 1, @@ -4795,7 +4795,7 @@ "code": 17, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "NVM", "singleton": 0, @@ -4811,7 +4811,7 @@ "code": 18, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "NVM", "singleton": 0, @@ -4827,7 +4827,7 @@ "code": 21, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -4843,7 +4843,7 @@ "code": 22, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -4859,7 +4859,7 @@ "code": 23, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -4875,7 +4875,7 @@ "code": 24, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -4999,11 +4999,11 @@ "reportableChange": 0 }, { - "name": "PresetsSchedulesEditable", + "name": "SetpointHoldExpiryTimestamp", "code": 82, "mfgCode": null, "side": "server", - "type": "boolean", + "type": "epoch_s", "included": 1, "storageOption": "RAM", "singleton": 0, diff --git a/examples/tv-app/tv-common/tv-app.matter b/examples/tv-app/tv-common/tv-app.matter index 02ef8118fa74df..6401ae8dad4ba9 100644 --- a/examples/tv-app/tv-common/tv-app.matter +++ b/examples/tv-app/tv-common/tv-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for switching devices between 'On' and 'Off' states. */ cluster OnOff = 6 { revision 6; diff --git a/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter b/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter index 0f42ef74d2fb94..f0e6fec3c429bb 100644 --- a/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter +++ b/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter b/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter index 7cc780ba68436e..319a66e0ba83ea 100644 --- a/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter +++ b/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/examples/window-app/common/window-app.matter b/examples/window-app/common/window-app.matter index 446a3fb3f64e80..17a6bc61bcd3d3 100644 --- a/examples/window-app/common/window-app.matter +++ b/examples/window-app/common/window-app.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; diff --git a/scripts/rules.matterlint b/scripts/rules.matterlint index 43b9b5887582b4..16c1fa56e1de1e 100644 --- a/scripts/rules.matterlint +++ b/scripts/rules.matterlint @@ -44,6 +44,8 @@ load "../src/app/zap-templates/zcl/data-model/chip/flow-measurement-cluster.xml" load "../src/app/zap-templates/zcl/data-model/chip/general-commissioning-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/general-diagnostics-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/global-attributes.xml"; +load "../src/app/zap-templates/zcl/data-model/chip/global-bitmaps.xml"; +load "../src/app/zap-templates/zcl/data-model/chip/global-enums.xml"; load "../src/app/zap-templates/zcl/data-model/chip/global-structs.xml"; load "../src/app/zap-templates/zcl/data-model/chip/groups-cluster.xml"; load "../src/app/zap-templates/zcl/data-model/chip/group-key-mgmt-cluster.xml"; diff --git a/scripts/tools/zap/tests/inputs/all-clusters-app.zap b/scripts/tools/zap/tests/inputs/all-clusters-app.zap index 570e1711e53d6b..1cbd309ffa123a 100644 --- a/scripts/tools/zap/tests/inputs/all-clusters-app.zap +++ b/scripts/tools/zap/tests/inputs/all-clusters-app.zap @@ -17,13 +17,6 @@ } ], "package": [ - { - "pathRelativity": "relativeToZap", - "path": "../../../../../src/app/zap-templates/app-templates.json", - "type": "gen-templates-json", - "category": "matter", - "version": "chip-v1" - }, { "pathRelativity": "relativeToZap", "path": "../../../../../src/app/zap-templates/zcl/zcl-with-test-extensions.json", @@ -31,6 +24,13 @@ "category": "matter", "version": 1, "description": "Matter SDK ZCL data with some extensions" + }, + { + "pathRelativity": "relativeToZap", + "path": "../../../../../src/app/zap-templates/app-templates.json", + "type": "gen-templates-json", + "category": "matter", + "version": "chip-v1" } ], "endpointTypes": [ @@ -15920,6 +15920,38 @@ "source": "client", "isIncoming": 1, "isEnabled": 1 + }, + { + "name": "SetActiveScheduleRequest", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SetActivePresetRequest", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AtomicResponse", + "code": 253, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AtomicRequest", + "code": 254, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 } ], "attributes": [ @@ -16008,7 +16040,7 @@ "code": 17, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -16024,7 +16056,7 @@ "code": 18, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -16040,7 +16072,7 @@ "code": 21, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -16056,7 +16088,7 @@ "code": 22, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -16072,7 +16104,7 @@ "code": 23, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -16088,7 +16120,7 @@ "code": 24, "mfgCode": null, "side": "server", - "type": "int16s", + "type": "temperature", "included": 1, "storageOption": "RAM", "singleton": 0, @@ -16291,41 +16323,9 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "PresetsSchedulesEditable", - "code": 82, - "mfgCode": null, - "side": "server", - "type": "boolean", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, - { - "name": "TemperatureSetpointHoldPolicy", - "code": 83, - "mfgCode": null, - "side": "server", - "type": "TemperatureSetpointHoldPolicyBitmap", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "0", - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "SetpointHoldExpiryTimestamp", - "code": 84, + "code": 82, "mfgCode": null, "side": "server", "type": "epoch_s", @@ -16339,22 +16339,6 @@ "maxInterval": 65534, "reportableChange": 0 }, - { - "name": "QueuedPreset", - "code": 85, - "mfgCode": null, - "side": "server", - "type": "QueuedPresetStruct", - "included": 1, - "storageOption": "External", - "singleton": 0, - "bounded": 0, - "defaultValue": null, - "reportable": 1, - "minInterval": 1, - "maxInterval": 65534, - "reportableChange": 0 - }, { "name": "GeneratedCommandList", "code": 65528, diff --git a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/IMClusterCommandHandler.cpp b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/IMClusterCommandHandler.cpp index 1594a2db87dfeb..dbfbc68a2bcf2f 100644 --- a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/IMClusterCommandHandler.cpp +++ b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/IMClusterCommandHandler.cpp @@ -1420,6 +1420,33 @@ void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandP } break; } + case Commands::SetActiveScheduleRequest::Id: { + Commands::SetActiveScheduleRequest::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfThermostatClusterSetActiveScheduleRequestCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + case Commands::SetActivePresetRequest::Id: { + Commands::SetActivePresetRequest::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfThermostatClusterSetActivePresetRequestCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + case Commands::AtomicRequest::Id: { + Commands::AtomicRequest::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfThermostatClusterAtomicRequestCallback(apCommandObj, aCommandPath, commandData); + } + break; + } default: { // Unrecognized command ID, error status will apply. apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::UnsupportedCommand); diff --git a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/access.h b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/access.h index 9b4ddb220986ad..8f0c8ef6cb729a 100644 --- a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/access.h +++ b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/access.h @@ -400,6 +400,7 @@ 0x00000062, /* Cluster: Scenes Management, Command: RemoveScene, Privilege: manage */ \ 0x00000062, /* Cluster: Scenes Management, Command: RemoveAllScenes, Privilege: manage */ \ 0x00000062, /* Cluster: Scenes Management, Command: StoreScene, Privilege: manage */ \ + 0x00000201, /* Cluster: Thermostat, Command: AtomicRequest, Privilege: manage */ \ 0xFFF1FC06, /* Cluster: Fault Injection, Command: FailAtFault, Privilege: manage */ \ 0xFFF1FC06, /* Cluster: Fault Injection, Command: FailRandomlyAtFault, Privilege: manage */ \ } @@ -449,6 +450,7 @@ 0x00000002, /* Cluster: Scenes Management, Command: RemoveScene, Privilege: manage */ \ 0x00000003, /* Cluster: Scenes Management, Command: RemoveAllScenes, Privilege: manage */ \ 0x00000004, /* Cluster: Scenes Management, Command: StoreScene, Privilege: manage */ \ + 0x000000FE, /* Cluster: Thermostat, Command: AtomicRequest, Privilege: manage */ \ 0x00000000, /* Cluster: Fault Injection, Command: FailAtFault, Privilege: manage */ \ 0x00000001, /* Cluster: Fault Injection, Command: FailRandomlyAtFault, Privilege: manage */ \ } @@ -498,6 +500,7 @@ chip::Access::Privilege::kManage, /* Cluster: Scenes Management, Command: RemoveScene, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Scenes Management, Command: RemoveAllScenes, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Scenes Management, Command: StoreScene, Privilege: manage */ \ + chip::Access::Privilege::kManage, /* Cluster: Thermostat, Command: AtomicRequest, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Fault Injection, Command: FailAtFault, Privilege: manage */ \ chip::Access::Privilege::kManage, /* Cluster: Fault Injection, Command: FailRandomlyAtFault, Privilege: manage */ \ } diff --git a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h index c60950077fb372..3423dab4902623 100644 --- a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h +++ b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h @@ -307,7 +307,7 @@ { (uint16_t) 0xBB8, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* MaxHeatSetpointLimit */ \ { (uint16_t) 0x640, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* MinCoolSetpointLimit */ \ { (uint16_t) 0xC80, (uint16_t) -0x6AB3, (uint16_t) 0x7FFF }, /* MaxCoolSetpointLimit */ \ - { (uint16_t) 0x19, (uint16_t) 0x0, (uint16_t) 0x19 }, /* MinSetpointDeadBand */ \ + { (uint16_t) 0x19, (uint16_t) 0x0, (uint16_t) 0x7F }, /* MinSetpointDeadBand */ \ { (uint16_t) 0x4, (uint16_t) 0x0, (uint16_t) 0x5 }, /* ControlSequenceOfOperation */ \ { (uint16_t) 0x1, (uint16_t) 0x0, (uint16_t) 0x9 }, /* SystemMode */ \ \ @@ -355,7 +355,7 @@ } // This is an array of EmberAfAttributeMetadata structures. -#define GENERATED_ATTRIBUTE_COUNT 1055 +#define GENERATED_ATTRIBUTE_COUNT 1054 #define GENERATED_ATTRIBUTES \ { \ \ @@ -1367,17 +1367,17 @@ { ZAP_SIMPLE_DEFAULT(0x0BB8), 0x00000004, 2, ZAP_TYPE(TEMPERATURE), 0 }, /* AbsMaxHeatSetpointLimit */ \ { ZAP_SIMPLE_DEFAULT(0x0640), 0x00000005, 2, ZAP_TYPE(TEMPERATURE), 0 }, /* AbsMinCoolSetpointLimit */ \ { ZAP_SIMPLE_DEFAULT(0x0C80), 0x00000006, 2, ZAP_TYPE(TEMPERATURE), 0 }, /* AbsMaxCoolSetpointLimit */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(13), 0x00000011, 2, ZAP_TYPE(INT16S), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(13), 0x00000011, 2, ZAP_TYPE(TEMPERATURE), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* OccupiedCoolingSetpoint */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(14), 0x00000012, 2, ZAP_TYPE(INT16S), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(14), 0x00000012, 2, ZAP_TYPE(TEMPERATURE), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* OccupiedHeatingSetpoint */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(15), 0x00000015, 2, ZAP_TYPE(INT16S), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(15), 0x00000015, 2, ZAP_TYPE(TEMPERATURE), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* MinHeatSetpointLimit */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(16), 0x00000016, 2, ZAP_TYPE(INT16S), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(16), 0x00000016, 2, ZAP_TYPE(TEMPERATURE), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* MaxHeatSetpointLimit */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(17), 0x00000017, 2, ZAP_TYPE(INT16S), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(17), 0x00000017, 2, ZAP_TYPE(TEMPERATURE), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* MinCoolSetpointLimit */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(18), 0x00000018, 2, ZAP_TYPE(INT16S), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(18), 0x00000018, 2, ZAP_TYPE(TEMPERATURE), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* MaxCoolSetpointLimit */ \ { ZAP_MIN_MAX_DEFAULTS_INDEX(19), 0x00000019, 1, ZAP_TYPE(INT8S), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* MinSetpointDeadBand */ \ @@ -1399,8 +1399,7 @@ ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* Presets */ \ { ZAP_EMPTY_DEFAULT(), 0x00000051, 0, ZAP_TYPE(ARRAY), \ ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* Schedules */ \ - { ZAP_EMPTY_DEFAULT(), 0x00000052, 1, ZAP_TYPE(BOOLEAN), 0 }, /* PresetsSchedulesEditable */ \ - { ZAP_SIMPLE_DEFAULT(0), 0x00000053, 4, ZAP_TYPE(EPOCH_S), \ + { ZAP_EMPTY_DEFAULT(), 0x00000052, 4, ZAP_TYPE(EPOCH_S), \ ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* SetpointHoldExpiryTimestamp */ \ { ZAP_SIMPLE_DEFAULT(0x0023), 0x0000FFFC, 4, ZAP_TYPE(BITMAP32), 0 }, /* FeatureMap */ \ { ZAP_SIMPLE_DEFAULT(6), 0x0000FFFD, 2, ZAP_TYPE(INT16U), 0 }, /* ClusterRevision */ \ @@ -2591,13 +2590,19 @@ /* Endpoint: 1, Cluster: Thermostat (server) */\ /* AcceptedCommandList (index=241) */ \ 0x00000000 /* SetpointRaiseLower */, \ + 0x00000005 /* SetActiveScheduleRequest */, \ + 0x00000006 /* SetActivePresetRequest */, \ + 0x000000FE /* AtomicRequest */, \ + chip::kInvalidCommandId /* end of list */, \ + /* GeneratedCommandList (index=246)*/ \ + 0x000000FD /* AtomicResponse */, \ chip::kInvalidCommandId /* end of list */, \ /* Endpoint: 1, Cluster: Fan Control (server) */\ - /* AcceptedCommandList (index=243) */ \ + /* AcceptedCommandList (index=248) */ \ 0x00000000 /* Step */, \ chip::kInvalidCommandId /* end of list */, \ /* Endpoint: 1, Cluster: Color Control (server) */\ - /* AcceptedCommandList (index=245) */ \ + /* AcceptedCommandList (index=250) */ \ 0x00000000 /* MoveToHue */, \ 0x00000001 /* MoveHue */, \ 0x00000002 /* StepHue */, \ @@ -2619,11 +2624,11 @@ 0x0000004C /* StepColorTemperature */, \ chip::kInvalidCommandId /* end of list */, \ /* Endpoint: 1, Cluster: Low Power (server) */\ - /* AcceptedCommandList (index=265) */ \ + /* AcceptedCommandList (index=270) */ \ 0x00000000 /* Sleep */, \ chip::kInvalidCommandId /* end of list */, \ /* Endpoint: 1, Cluster: Unit Testing (server) */\ - /* AcceptedCommandList (index=267) */ \ + /* AcceptedCommandList (index=272) */ \ 0x00000000 /* Test */, \ 0x00000001 /* TestNotHandled */, \ 0x00000002 /* TestSpecific */, \ @@ -2646,7 +2651,7 @@ 0x00000017 /* TestSecondBatchHelperRequest */, \ 0xFFF200AA /* TestDifferentVendorMeiRequest */, \ chip::kInvalidCommandId /* end of list */, \ - /* GeneratedCommandList (index=289)*/ \ + /* GeneratedCommandList (index=294)*/ \ 0x00000000 /* TestSpecificResponse */, \ 0x00000001 /* TestAddArgumentsResponse */, \ 0x00000004 /* TestListInt8UReverseResponse */, \ @@ -2660,12 +2665,12 @@ 0xFFF200BB /* TestDifferentVendorMeiResponse */, \ chip::kInvalidCommandId /* end of list */, \ /* Endpoint: 2, Cluster: Identify (server) */\ - /* AcceptedCommandList (index=301) */ \ + /* AcceptedCommandList (index=306) */ \ 0x00000000 /* Identify */, \ 0x00000040 /* TriggerEffect */, \ chip::kInvalidCommandId /* end of list */, \ /* Endpoint: 2, Cluster: Groups (server) */\ - /* AcceptedCommandList (index=304) */ \ + /* AcceptedCommandList (index=309) */ \ 0x00000000 /* AddGroup */, \ 0x00000001 /* ViewGroup */, \ 0x00000002 /* GetGroupMembership */, \ @@ -2673,14 +2678,14 @@ 0x00000004 /* RemoveAllGroups */, \ 0x00000005 /* AddGroupIfIdentifying */, \ chip::kInvalidCommandId /* end of list */, \ - /* GeneratedCommandList (index=311)*/ \ + /* GeneratedCommandList (index=316)*/ \ 0x00000000 /* AddGroupResponse */, \ 0x00000001 /* ViewGroupResponse */, \ 0x00000002 /* GetGroupMembershipResponse */, \ 0x00000003 /* RemoveGroupResponse */, \ chip::kInvalidCommandId /* end of list */, \ /* Endpoint: 2, Cluster: On/Off (server) */\ - /* AcceptedCommandList (index=316) */ \ + /* AcceptedCommandList (index=321) */ \ 0x00000000 /* Off */, \ 0x00000001 /* On */, \ 0x00000002 /* Toggle */, \ @@ -2689,7 +2694,7 @@ 0x00000042 /* OnWithTimedOff */, \ chip::kInvalidCommandId /* end of list */, \ /* Endpoint: 2, Cluster: Scenes Management (server) */\ - /* AcceptedCommandList (index=323) */ \ + /* AcceptedCommandList (index=328) */ \ 0x00000000 /* AddScene */, \ 0x00000001 /* ViewScene */, \ 0x00000002 /* RemoveScene */, \ @@ -2699,7 +2704,7 @@ 0x00000006 /* GetSceneMembership */, \ 0x00000040 /* CopyScene */, \ chip::kInvalidCommandId /* end of list */, \ - /* GeneratedCommandList (index=332)*/ \ + /* GeneratedCommandList (index=337)*/ \ 0x00000000 /* AddSceneResponse */, \ 0x00000001 /* ViewSceneResponse */, \ 0x00000002 /* RemoveSceneResponse */, \ @@ -2709,7 +2714,7 @@ 0x00000040 /* CopySceneResponse */, \ chip::kInvalidCommandId /* end of list */, \ /* Endpoint: 65534, Cluster: Network Commissioning (server) */\ - /* AcceptedCommandList (index=340) */ \ + /* AcceptedCommandList (index=345) */ \ 0x00000000 /* ScanNetworks */, \ 0x00000002 /* AddOrUpdateWiFiNetwork */, \ 0x00000003 /* AddOrUpdateThreadNetwork */, \ @@ -2717,7 +2722,7 @@ 0x00000006 /* ConnectNetwork */, \ 0x00000008 /* ReorderNetwork */, \ chip::kInvalidCommandId /* end of list */, \ - /* GeneratedCommandList (index=347)*/ \ + /* GeneratedCommandList (index=352)*/ \ 0x00000001 /* ScanNetworksResponse */, \ 0x00000005 /* NetworkConfigResponse */, \ 0x00000007 /* ConnectNetworkResponse */, \ @@ -3748,24 +3753,24 @@ /* Endpoint: 1, Cluster: Thermostat (server) */ \ .clusterId = 0x00000201, \ .attributes = ZAP_ATTRIBUTE_INDEX(616), \ - .attributeCount = 27, \ - .clusterSize = 73, \ + .attributeCount = 26, \ + .clusterSize = 72, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(PRE_ATTRIBUTE_CHANGED_FUNCTION), \ .functions = chipFuncArrayThermostatServer, \ .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 241 ), \ - .generatedCommandList = nullptr, \ + .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 246 ), \ .eventList = nullptr, \ .eventCount = 0, \ },\ { \ /* Endpoint: 1, Cluster: Fan Control (server) */ \ .clusterId = 0x00000202, \ - .attributes = ZAP_ATTRIBUTE_INDEX(643), \ + .attributes = ZAP_ATTRIBUTE_INDEX(642), \ .attributeCount = 14, \ .clusterSize = 18, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(ATTRIBUTE_CHANGED_FUNCTION) | ZAP_CLUSTER_MASK(PRE_ATTRIBUTE_CHANGED_FUNCTION), \ .functions = chipFuncArrayFanControlServer, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 243 ), \ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 248 ), \ .generatedCommandList = nullptr, \ .eventList = nullptr, \ .eventCount = 0, \ @@ -3773,7 +3778,7 @@ { \ /* Endpoint: 1, Cluster: Thermostat User Interface Configuration (server) */ \ .clusterId = 0x00000204, \ - .attributes = ZAP_ATTRIBUTE_INDEX(657), \ + .attributes = ZAP_ATTRIBUTE_INDEX(656), \ .attributeCount = 5, \ .clusterSize = 9, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(PRE_ATTRIBUTE_CHANGED_FUNCTION), \ @@ -3786,12 +3791,12 @@ { \ /* Endpoint: 1, Cluster: Color Control (server) */ \ .clusterId = 0x00000300, \ - .attributes = ZAP_ATTRIBUTE_INDEX(662), \ + .attributes = ZAP_ATTRIBUTE_INDEX(661), \ .attributeCount = 54, \ .clusterSize = 345, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(SHUTDOWN_FUNCTION), \ .functions = chipFuncArrayColorControlServer, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 245 ), \ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 250 ), \ .generatedCommandList = nullptr, \ .eventList = nullptr, \ .eventCount = 0, \ @@ -3799,7 +3804,7 @@ { \ /* Endpoint: 1, Cluster: Ballast Configuration (server) */ \ .clusterId = 0x00000301, \ - .attributes = ZAP_ATTRIBUTE_INDEX(716), \ + .attributes = ZAP_ATTRIBUTE_INDEX(715), \ .attributeCount = 16, \ .clusterSize = 58, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3812,7 +3817,7 @@ { \ /* Endpoint: 1, Cluster: Illuminance Measurement (server) */ \ .clusterId = 0x00000400, \ - .attributes = ZAP_ATTRIBUTE_INDEX(732), \ + .attributes = ZAP_ATTRIBUTE_INDEX(731), \ .attributeCount = 7, \ .clusterSize = 15, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3825,7 +3830,7 @@ { \ /* Endpoint: 1, Cluster: Temperature Measurement (server) */ \ .clusterId = 0x00000402, \ - .attributes = ZAP_ATTRIBUTE_INDEX(739), \ + .attributes = ZAP_ATTRIBUTE_INDEX(738), \ .attributeCount = 6, \ .clusterSize = 14, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3838,7 +3843,7 @@ { \ /* Endpoint: 1, Cluster: Pressure Measurement (server) */ \ .clusterId = 0x00000403, \ - .attributes = ZAP_ATTRIBUTE_INDEX(745), \ + .attributes = ZAP_ATTRIBUTE_INDEX(744), \ .attributeCount = 5, \ .clusterSize = 12, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3851,7 +3856,7 @@ { \ /* Endpoint: 1, Cluster: Flow Measurement (server) */ \ .clusterId = 0x00000404, \ - .attributes = ZAP_ATTRIBUTE_INDEX(750), \ + .attributes = ZAP_ATTRIBUTE_INDEX(749), \ .attributeCount = 6, \ .clusterSize = 14, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3864,7 +3869,7 @@ { \ /* Endpoint: 1, Cluster: Relative Humidity Measurement (server) */ \ .clusterId = 0x00000405, \ - .attributes = ZAP_ATTRIBUTE_INDEX(756), \ + .attributes = ZAP_ATTRIBUTE_INDEX(755), \ .attributeCount = 6, \ .clusterSize = 14, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3877,7 +3882,7 @@ { \ /* Endpoint: 1, Cluster: Occupancy Sensing (server) */ \ .clusterId = 0x00000406, \ - .attributes = ZAP_ATTRIBUTE_INDEX(762), \ + .attributes = ZAP_ATTRIBUTE_INDEX(761), \ .attributeCount = 5, \ .clusterSize = 9, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ @@ -3890,7 +3895,7 @@ { \ /* Endpoint: 1, Cluster: Carbon Monoxide Concentration Measurement (server) */ \ .clusterId = 0x0000040C, \ - .attributes = ZAP_ATTRIBUTE_INDEX(767), \ + .attributes = ZAP_ATTRIBUTE_INDEX(766), \ .attributeCount = 13, \ .clusterSize = 2, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3903,7 +3908,7 @@ { \ /* Endpoint: 1, Cluster: Carbon Dioxide Concentration Measurement (server) */ \ .clusterId = 0x0000040D, \ - .attributes = ZAP_ATTRIBUTE_INDEX(780), \ + .attributes = ZAP_ATTRIBUTE_INDEX(779), \ .attributeCount = 13, \ .clusterSize = 2, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3916,7 +3921,7 @@ { \ /* Endpoint: 1, Cluster: Nitrogen Dioxide Concentration Measurement (server) */ \ .clusterId = 0x00000413, \ - .attributes = ZAP_ATTRIBUTE_INDEX(793), \ + .attributes = ZAP_ATTRIBUTE_INDEX(792), \ .attributeCount = 13, \ .clusterSize = 2, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3929,7 +3934,7 @@ { \ /* Endpoint: 1, Cluster: Ozone Concentration Measurement (server) */ \ .clusterId = 0x00000415, \ - .attributes = ZAP_ATTRIBUTE_INDEX(806), \ + .attributes = ZAP_ATTRIBUTE_INDEX(805), \ .attributeCount = 13, \ .clusterSize = 2, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3942,7 +3947,7 @@ { \ /* Endpoint: 1, Cluster: PM2.5 Concentration Measurement (server) */ \ .clusterId = 0x0000042A, \ - .attributes = ZAP_ATTRIBUTE_INDEX(819), \ + .attributes = ZAP_ATTRIBUTE_INDEX(818), \ .attributeCount = 13, \ .clusterSize = 2, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3955,7 +3960,7 @@ { \ /* Endpoint: 1, Cluster: Formaldehyde Concentration Measurement (server) */ \ .clusterId = 0x0000042B, \ - .attributes = ZAP_ATTRIBUTE_INDEX(832), \ + .attributes = ZAP_ATTRIBUTE_INDEX(831), \ .attributeCount = 13, \ .clusterSize = 2, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3968,7 +3973,7 @@ { \ /* Endpoint: 1, Cluster: PM1 Concentration Measurement (server) */ \ .clusterId = 0x0000042C, \ - .attributes = ZAP_ATTRIBUTE_INDEX(845), \ + .attributes = ZAP_ATTRIBUTE_INDEX(844), \ .attributeCount = 13, \ .clusterSize = 2, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3981,7 +3986,7 @@ { \ /* Endpoint: 1, Cluster: PM10 Concentration Measurement (server) */ \ .clusterId = 0x0000042D, \ - .attributes = ZAP_ATTRIBUTE_INDEX(858), \ + .attributes = ZAP_ATTRIBUTE_INDEX(857), \ .attributeCount = 13, \ .clusterSize = 2, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -3994,7 +3999,7 @@ { \ /* Endpoint: 1, Cluster: Total Volatile Organic Compounds Concentration Measurement (server) */ \ .clusterId = 0x0000042E, \ - .attributes = ZAP_ATTRIBUTE_INDEX(871), \ + .attributes = ZAP_ATTRIBUTE_INDEX(870), \ .attributeCount = 13, \ .clusterSize = 2, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -4007,7 +4012,7 @@ { \ /* Endpoint: 1, Cluster: Radon Concentration Measurement (server) */ \ .clusterId = 0x0000042F, \ - .attributes = ZAP_ATTRIBUTE_INDEX(884), \ + .attributes = ZAP_ATTRIBUTE_INDEX(883), \ .attributeCount = 13, \ .clusterSize = 2, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -4020,7 +4025,7 @@ { \ /* Endpoint: 1, Cluster: Wake on LAN (server) */ \ .clusterId = 0x00000503, \ - .attributes = ZAP_ATTRIBUTE_INDEX(897), \ + .attributes = ZAP_ATTRIBUTE_INDEX(896), \ .attributeCount = 3, \ .clusterSize = 19, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -4033,12 +4038,12 @@ { \ /* Endpoint: 1, Cluster: Low Power (server) */ \ .clusterId = 0x00000508, \ - .attributes = ZAP_ATTRIBUTE_INDEX(900), \ + .attributes = ZAP_ATTRIBUTE_INDEX(899), \ .attributeCount = 2, \ .clusterSize = 6, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ .functions = NULL, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 265 ), \ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 270 ), \ .generatedCommandList = nullptr, \ .eventList = nullptr, \ .eventCount = 0, \ @@ -4046,7 +4051,7 @@ { \ /* Endpoint: 1, Cluster: Electrical Measurement (server) */ \ .clusterId = 0x00000B04, \ - .attributes = ZAP_ATTRIBUTE_INDEX(902), \ + .attributes = ZAP_ATTRIBUTE_INDEX(901), \ .attributeCount = 13, \ .clusterSize = 32, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -4059,25 +4064,25 @@ { \ /* Endpoint: 1, Cluster: Unit Testing (server) */ \ .clusterId = 0xFFF1FC05, \ - .attributes = ZAP_ATTRIBUTE_INDEX(915), \ + .attributes = ZAP_ATTRIBUTE_INDEX(914), \ .attributeCount = 84, \ .clusterSize = 2290, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ .functions = NULL, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 267 ), \ - .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 289 ), \ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 272 ), \ + .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 294 ), \ .eventList = ZAP_GENERATED_EVENTS_INDEX( 59 ), \ .eventCount = 3, \ },\ { \ /* Endpoint: 2, Cluster: Identify (server) */ \ .clusterId = 0x00000003, \ - .attributes = ZAP_ATTRIBUTE_INDEX(999), \ + .attributes = ZAP_ATTRIBUTE_INDEX(998), \ .attributeCount = 4, \ .clusterSize = 9, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(ATTRIBUTE_CHANGED_FUNCTION), \ .functions = chipFuncArrayIdentifyServer, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 301 ), \ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 306 ), \ .generatedCommandList = nullptr, \ .eventList = nullptr, \ .eventCount = 0, \ @@ -4085,25 +4090,25 @@ { \ /* Endpoint: 2, Cluster: Groups (server) */ \ .clusterId = 0x00000004, \ - .attributes = ZAP_ATTRIBUTE_INDEX(1003), \ + .attributes = ZAP_ATTRIBUTE_INDEX(1002), \ .attributeCount = 3, \ .clusterSize = 7, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ .functions = chipFuncArrayGroupsServer, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 304 ), \ - .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 311 ), \ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 309 ), \ + .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 316 ), \ .eventList = nullptr, \ .eventCount = 0, \ },\ { \ /* Endpoint: 2, Cluster: On/Off (server) */ \ .clusterId = 0x00000006, \ - .attributes = ZAP_ATTRIBUTE_INDEX(1006), \ + .attributes = ZAP_ATTRIBUTE_INDEX(1005), \ .attributeCount = 7, \ .clusterSize = 13, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(SHUTDOWN_FUNCTION), \ .functions = chipFuncArrayOnOffServer, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 316 ), \ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 321 ), \ .generatedCommandList = nullptr, \ .eventList = nullptr, \ .eventCount = 0, \ @@ -4111,7 +4116,7 @@ { \ /* Endpoint: 2, Cluster: Descriptor (server) */ \ .clusterId = 0x0000001D, \ - .attributes = ZAP_ATTRIBUTE_INDEX(1013), \ + .attributes = ZAP_ATTRIBUTE_INDEX(1012), \ .attributeCount = 7, \ .clusterSize = 0, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -4124,7 +4129,7 @@ { \ /* Endpoint: 2, Cluster: Power Source (server) */ \ .clusterId = 0x0000002F, \ - .attributes = ZAP_ATTRIBUTE_INDEX(1020), \ + .attributes = ZAP_ATTRIBUTE_INDEX(1019), \ .attributeCount = 9, \ .clusterSize = 72, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -4137,20 +4142,20 @@ { \ /* Endpoint: 2, Cluster: Scenes Management (server) */ \ .clusterId = 0x00000062, \ - .attributes = ZAP_ATTRIBUTE_INDEX(1029), \ + .attributes = ZAP_ATTRIBUTE_INDEX(1028), \ .attributeCount = 5, \ .clusterSize = 16, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(SHUTDOWN_FUNCTION), \ .functions = chipFuncArrayScenesManagementServer, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 323 ), \ - .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 332 ), \ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 328 ), \ + .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 337 ), \ .eventList = nullptr, \ .eventCount = 0, \ },\ { \ /* Endpoint: 2, Cluster: Occupancy Sensing (server) */ \ .clusterId = 0x00000406, \ - .attributes = ZAP_ATTRIBUTE_INDEX(1034), \ + .attributes = ZAP_ATTRIBUTE_INDEX(1033), \ .attributeCount = 5, \ .clusterSize = 9, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ @@ -4163,7 +4168,7 @@ { \ /* Endpoint: 65534, Cluster: Descriptor (server) */ \ .clusterId = 0x0000001D, \ - .attributes = ZAP_ATTRIBUTE_INDEX(1039), \ + .attributes = ZAP_ATTRIBUTE_INDEX(1038), \ .attributeCount = 6, \ .clusterSize = 0, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -4176,13 +4181,13 @@ { \ /* Endpoint: 65534, Cluster: Network Commissioning (server) */ \ .clusterId = 0x00000031, \ - .attributes = ZAP_ATTRIBUTE_INDEX(1045), \ + .attributes = ZAP_ATTRIBUTE_INDEX(1044), \ .attributeCount = 10, \ .clusterSize = 0, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ .functions = NULL, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 340 ), \ - .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 347 ), \ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 345 ), \ + .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 352 ), \ .eventList = nullptr, \ .eventCount = 0, \ },\ @@ -4195,7 +4200,7 @@ // This is an array of EmberAfEndpointType structures. #define GENERATED_ENDPOINT_TYPES \ { \ - { ZAP_CLUSTER_INDEX(0), 29, 349 }, { ZAP_CLUSTER_INDEX(29), 74, 3522 }, { ZAP_CLUSTER_INDEX(103), 7, 126 }, \ + { ZAP_CLUSTER_INDEX(0), 29, 349 }, { ZAP_CLUSTER_INDEX(29), 74, 3521 }, { ZAP_CLUSTER_INDEX(103), 7, 126 }, \ { ZAP_CLUSTER_INDEX(110), 2, 0 }, \ } @@ -4208,7 +4213,7 @@ static_assert(ATTRIBUTE_LARGEST <= CHIP_CONFIG_MAX_ATTRIBUTE_STORE_ELEMENT_SIZE, #define ATTRIBUTE_SINGLETONS_SIZE (36) // Total size of attribute storage -#define ATTRIBUTE_MAX_SIZE (3997) +#define ATTRIBUTE_MAX_SIZE (3996) // Number of fixed endpoints #define FIXED_ENDPOINT_COUNT (4) diff --git a/src/app/clusters/thermostat-server/PresetStructWithOwnedMembers.cpp b/src/app/clusters/thermostat-server/PresetStructWithOwnedMembers.cpp index dfc395f6bee81d..78393fd22b708d 100644 --- a/src/app/clusters/thermostat-server/PresetStructWithOwnedMembers.cpp +++ b/src/app/clusters/thermostat-server/PresetStructWithOwnedMembers.cpp @@ -32,7 +32,7 @@ PresetStructWithOwnedMembers::PresetStructWithOwnedMembers(const PresetStruct::T *this = other; } -void PresetStructWithOwnedMembers::operator=(const PresetStruct::Type & other) +PresetStructWithOwnedMembers & PresetStructWithOwnedMembers::operator=(const PresetStruct::Type & other) { SetPresetScenario(other.presetScenario); CHIP_ERROR err = SetPresetHandle(other.presetHandle); @@ -48,6 +48,17 @@ void PresetStructWithOwnedMembers::operator=(const PresetStruct::Type & other) SetCoolingSetpoint(other.coolingSetpoint); SetHeatingSetpoint(other.heatingSetpoint); SetBuiltIn(other.builtIn); + return *this; +} + +PresetStructWithOwnedMembers & PresetStructWithOwnedMembers::operator=(const PresetStructWithOwnedMembers & other) +{ + if (this == &other) + { + return *this; + } + *this = static_cast(other); + return *this; } void PresetStructWithOwnedMembers::SetPresetScenario(PresetScenarioEnum enumValue) diff --git a/src/app/clusters/thermostat-server/PresetStructWithOwnedMembers.h b/src/app/clusters/thermostat-server/PresetStructWithOwnedMembers.h index 7161fb874989e2..8a2fa7f336c58b 100644 --- a/src/app/clusters/thermostat-server/PresetStructWithOwnedMembers.h +++ b/src/app/clusters/thermostat-server/PresetStructWithOwnedMembers.h @@ -42,7 +42,8 @@ struct PresetStructWithOwnedMembers : protected Structs::PresetStruct::Type public: PresetStructWithOwnedMembers() = default; PresetStructWithOwnedMembers(const Structs::PresetStruct::Type & other); - void operator=(const Structs::PresetStruct::Type & other); + PresetStructWithOwnedMembers & operator=(const Structs::PresetStruct::Type & other); + PresetStructWithOwnedMembers & operator=(const PresetStructWithOwnedMembers & other); void SetPresetScenario(PresetScenarioEnum enumValue); CHIP_ERROR SetPresetHandle(const DataModel::Nullable & newPresetHandle); diff --git a/src/app/clusters/thermostat-server/thermostat-delegate.h b/src/app/clusters/thermostat-server/thermostat-delegate.h index 86c1e532b92fc2..0c09b9dd4d70fc 100644 --- a/src/app/clusters/thermostat-server/thermostat-delegate.h +++ b/src/app/clusters/thermostat-server/thermostat-delegate.h @@ -80,6 +80,11 @@ class Delegate */ virtual CHIP_ERROR SetActivePresetHandle(const DataModel::Nullable & newActivePresetHandle) = 0; + /** + * @brief Copies existing presets to the pending preset list + */ + virtual void InitializePendingPresets() = 0; + /** * @brief Appends a preset to the pending presets list maintained by the delegate. * The delegate must ensure it makes a copy of the provided preset and the data diff --git a/src/app/clusters/thermostat-server/thermostat-server.cpp b/src/app/clusters/thermostat-server/thermostat-server.cpp index 71c2f3d6fd6260..afdb1b12afe763 100644 --- a/src/app/clusters/thermostat-server/thermostat-server.cpp +++ b/src/app/clusters/thermostat-server/thermostat-server.cpp @@ -116,18 +116,19 @@ void TimerExpiredCallback(System::Layer * systemLayer, void * callbackContext) VerifyOrReturn(delegate != nullptr, ChipLogError(Zcl, "Delegate is null. Unable to handle timer expired")); delegate->ClearPendingPresetList(); - gThermostatAttrAccess.SetPresetsEditable(endpoint, false); + gThermostatAttrAccess.SetAtomicWrite(endpoint, false); + gThermostatAttrAccess.SetAtomicWriteScopedNodeId(endpoint, ScopedNodeId()); } /** - * @brief Schedules a timer for the given timeout in seconds. + * @brief Schedules a timer for the given timeout in milliseconds. * * @param[in] endpoint The endpoint to use. - * @param[in] timeoutSeconds The timeout in seconds. + * @param[in] timeoutMilliseconds The timeout in milliseconds. */ -void ScheduleTimer(EndpointId endpoint, uint16_t timeoutSeconds) +void ScheduleTimer(EndpointId endpoint, System::Clock::Milliseconds16 timeout) { - DeviceLayer::SystemLayer().StartTimer(System::Clock::Seconds16(timeoutSeconds), TimerExpiredCallback, + DeviceLayer::SystemLayer().StartTimer(timeout, TimerExpiredCallback, reinterpret_cast(static_cast(endpoint))); } @@ -141,18 +142,6 @@ void ClearTimer(EndpointId endpoint) DeviceLayer::SystemLayer().CancelTimer(TimerExpiredCallback, reinterpret_cast(static_cast(endpoint))); } -/** - * @brief Extends the currently scheduled timer to a new timeout value in seconds - * - * @param[in] endpoint The endpoint to use. - * @param[in] timeoutSeconds The timeout in seconds to extend the timer to. - */ -void ExtendTimer(EndpointId endpoint, uint16_t timeoutSeconds) -{ - DeviceLayer::SystemLayer().ExtendTimerTo(System::Clock::Seconds16(timeoutSeconds), TimerExpiredCallback, - reinterpret_cast(static_cast(endpoint))); -} - /** * @brief Checks if the preset is built-in * @@ -203,40 +192,21 @@ ScopedNodeId GetSourceScopedNodeId(CommandHandler * commandObj) } /** - * @brief Utility to clean up state by clearing the pending presets list, canceling the timer - * and setting PresetsEditable to false and clear the originator scoped node id. + * @brief Discards pending atomic writes and atomic state. * * @param[in] delegate The delegate to use. * @param[in] endpoint The endpoint to use. + * */ -void CleanUp(Delegate * delegate, EndpointId endpoint) +void resetAtomicWrite(Delegate * delegate, EndpointId endpoint) { if (delegate != nullptr) { delegate->ClearPendingPresetList(); } ClearTimer(endpoint); - gThermostatAttrAccess.SetPresetsEditable(endpoint, false); - gThermostatAttrAccess.SetOriginatorScopedNodeId(endpoint, ScopedNodeId()); -} - -/** - * @brief Sends a response for the command and cleans up state by calling CleanUp() - * - * @param[in] delegate The delegate to use. - * @param[in] endpoint The endpoint to use. - * @param[in] commandObj The command handler to use to add the status response. - * @param[in] commandPath The command path. - * @param[in] status The status code to send as the response. - * - * @return true to indicate the response has been sent and command has been handled. - */ -bool SendResponseAndCleanUp(Delegate * delegate, EndpointId endpoint, CommandHandler * commandObj, - const ConcreteCommandPath & commandPath, imcode status) -{ - commandObj->AddStatus(commandPath, status); - CleanUp(delegate, endpoint); - return true; + gThermostatAttrAccess.SetAtomicWrite(endpoint, false); + gThermostatAttrAccess.SetAtomicWriteScopedNodeId(endpoint, ScopedNodeId()); } /** @@ -277,8 +247,8 @@ bool MatchingPendingPresetExists(Delegate * delegate, const PresetStructWithOwne } /** - * @brief Finds and returns an entry in the Presets attribute list that matches a preset. - * The presetHandle of the two presets must match. + * @brief Finds and returns an entry in the Presets attribute list that matches + * a preset, if such an entry exists. The presetToMatch must have a preset handle. * * @param[in] delegate The delegate to use. * @param[in] presetToMatch The preset to match with. @@ -286,7 +256,7 @@ bool MatchingPendingPresetExists(Delegate * delegate, const PresetStructWithOwne * * @return true if a matching entry was found in the presets attribute list, false otherwise. */ -bool GetMatchingPresetInPresets(Delegate * delegate, const PresetStructWithOwnedMembers & presetToMatch, +bool GetMatchingPresetInPresets(Delegate * delegate, const PresetStruct::Type & presetToMatch, PresetStructWithOwnedMembers & matchingPreset) { VerifyOrReturnValue(delegate != nullptr, false); @@ -305,7 +275,8 @@ bool GetMatchingPresetInPresets(Delegate * delegate, const PresetStructWithOwned return false; } - if (PresetHandlesExistAndMatch(matchingPreset, presetToMatch)) + // Note: presets coming from our delegate always have a handle. + if (presetToMatch.presetHandle.Value().data_equal(matchingPreset.GetPresetHandle().Value())) { return true; } @@ -661,50 +632,70 @@ void SetDefaultDelegate(EndpointId endpoint, Delegate * delegate) } } -void ThermostatAttrAccess::SetPresetsEditable(EndpointId endpoint, bool presetEditable) +void ThermostatAttrAccess::SetAtomicWrite(EndpointId endpoint, bool inProgress) { uint16_t ep = emberAfGetClusterServerEndpointIndex(endpoint, Thermostat::Id, MATTER_DM_THERMOSTAT_CLUSTER_SERVER_ENDPOINT_COUNT); - if (ep < ArraySize(mPresetsEditables)) + if (ep < ArraySize(mAtomicWriteState)) { - mPresetsEditables[ep] = presetEditable; + mAtomicWriteState[ep] = inProgress; } } -bool ThermostatAttrAccess::GetPresetsEditable(EndpointId endpoint) +bool ThermostatAttrAccess::InAtomicWrite(EndpointId endpoint) { - bool presetEditable = false; + bool inAtomicWrite = false; uint16_t ep = emberAfGetClusterServerEndpointIndex(endpoint, Thermostat::Id, MATTER_DM_THERMOSTAT_CLUSTER_SERVER_ENDPOINT_COUNT); - if (ep < ArraySize(mPresetsEditables)) + if (ep < ArraySize(mAtomicWriteState)) + { + inAtomicWrite = mAtomicWriteState[ep]; + } + return inAtomicWrite; +} + +bool ThermostatAttrAccess::InAtomicWrite(const Access::SubjectDescriptor & subjectDescriptor, EndpointId endpoint) +{ + if (!InAtomicWrite(endpoint)) + { + return false; + } + return subjectDescriptor.authMode == Access::AuthMode::kCase && + GetAtomicWriteScopedNodeId(endpoint) == ScopedNodeId(subjectDescriptor.subject, subjectDescriptor.fabricIndex); +} + +bool ThermostatAttrAccess::InAtomicWrite(CommandHandler * commandObj, EndpointId endpoint) +{ + if (!InAtomicWrite(endpoint)) { - presetEditable = mPresetsEditables[ep]; + return false; } - return presetEditable; + ScopedNodeId sourceNodeId = GetSourceScopedNodeId(commandObj); + return GetAtomicWriteScopedNodeId(endpoint) == sourceNodeId; } -void ThermostatAttrAccess::SetOriginatorScopedNodeId(EndpointId endpoint, ScopedNodeId originatorNodeId) +void ThermostatAttrAccess::SetAtomicWriteScopedNodeId(EndpointId endpoint, ScopedNodeId originatorNodeId) { uint16_t ep = emberAfGetClusterServerEndpointIndex(endpoint, Thermostat::Id, MATTER_DM_THERMOSTAT_CLUSTER_SERVER_ENDPOINT_COUNT); - if (ep < ArraySize(mPresetEditRequestOriginatorNodeIds)) + if (ep < ArraySize(mAtomicWriteNodeIds)) { - mPresetEditRequestOriginatorNodeIds[ep] = originatorNodeId; + mAtomicWriteNodeIds[ep] = originatorNodeId; } } -ScopedNodeId ThermostatAttrAccess::GetOriginatorScopedNodeId(EndpointId endpoint) +ScopedNodeId ThermostatAttrAccess::GetAtomicWriteScopedNodeId(EndpointId endpoint) { ScopedNodeId originatorNodeId = ScopedNodeId(); uint16_t ep = emberAfGetClusterServerEndpointIndex(endpoint, Thermostat::Id, MATTER_DM_THERMOSTAT_CLUSTER_SERVER_ENDPOINT_COUNT); - if (ep < ArraySize(mPresetEditRequestOriginatorNodeIds)) + if (ep < ArraySize(mAtomicWriteNodeIds)) { - originatorNodeId = mPresetEditRequestOriginatorNodeIds[ep]; + originatorNodeId = mAtomicWriteNodeIds[ep]; } return originatorNodeId; } @@ -769,6 +760,23 @@ CHIP_ERROR ThermostatAttrAccess::Read(const ConcreteReadAttributePath & aPath, A Delegate * delegate = GetDelegate(aPath.mEndpointId); VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Delegate is null")); + auto & subjectDescriptor = aEncoder.GetSubjectDescriptor(); + if (InAtomicWrite(subjectDescriptor, aPath.mEndpointId)) + { + return aEncoder.EncodeList([delegate](const auto & encoder) -> CHIP_ERROR { + for (uint8_t i = 0; true; i++) + { + PresetStructWithOwnedMembers preset; + auto err = delegate->GetPendingPresetAtIndex(i, preset); + if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) + { + return CHIP_NO_ERROR; + } + ReturnErrorOnFailure(err); + ReturnErrorOnFailure(encoder.Encode(preset)); + } + }); + } return aEncoder.EncodeList([delegate](const auto & encoder) -> CHIP_ERROR { for (uint8_t i = 0; true; i++) { @@ -784,10 +792,6 @@ CHIP_ERROR ThermostatAttrAccess::Read(const ConcreteReadAttributePath & aPath, A }); } break; - case PresetsSchedulesEditable::Id: { - ReturnErrorOnFailure(aEncoder.Encode(GetPresetsEditable(aPath.mEndpointId))); - } - break; case ActivePresetHandle::Id: { Delegate * delegate = GetDelegate(aPath.mEndpointId); VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Delegate is null")); @@ -827,48 +831,24 @@ CHIP_ERROR ThermostatAttrAccess::Write(const ConcreteDataAttributePath & aPath, { VerifyOrDie(aPath.mClusterId == Thermostat::Id); - uint32_t ourFeatureMap; - bool localTemperatureNotExposedSupported = (FeatureMap::Get(aPath.mEndpointId, &ourFeatureMap) == imcode::Success) && - ((ourFeatureMap & to_underlying(Feature::kLocalTemperatureNotExposed)) != 0); + EndpointId endpoint = aPath.mEndpointId; + auto & subjectDescriptor = aDecoder.GetSubjectDescriptor(); + // Check atomic attributes first switch (aPath.mAttributeId) { - case RemoteSensing::Id: - if (localTemperatureNotExposedSupported) - { - uint8_t valueRemoteSensing; - ReturnErrorOnFailure(aDecoder.Decode(valueRemoteSensing)); - if (valueRemoteSensing & 0x01) // If setting bit 1 (LocalTemperature RemoteSensing bit) - { - return CHIP_IM_GLOBAL_STATUS(ConstraintError); - } - imcode status = RemoteSensing::Set(aPath.mEndpointId, valueRemoteSensing); - StatusIB statusIB(status); - return statusIB.ToChipError(); - } - break; case Presets::Id: { - EndpointId endpoint = aPath.mEndpointId; Delegate * delegate = GetDelegate(endpoint); VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INCORRECT_STATE, ChipLogError(Zcl, "Delegate is null")); // Presets are not editable, return INVALID_IN_STATE. - VerifyOrReturnError(GetPresetsEditable(endpoint), CHIP_IM_GLOBAL_STATUS(InvalidInState), + VerifyOrReturnError(InAtomicWrite(endpoint), CHIP_IM_GLOBAL_STATUS(InvalidInState), ChipLogError(Zcl, "Presets are not editable")); - // Check if the OriginatorScopedNodeId at the endpoint is the same as the node editing the presets, + // OK, we're in an atomic write, make sure the requesting node is the same one that started the atomic write, // otherwise return BUSY. - const Access::SubjectDescriptor subjectDescriptor = aDecoder.GetSubjectDescriptor(); - ScopedNodeId scopedNodeId = ScopedNodeId(); - - // Get the node id if the authentication mode is CASE. - if (subjectDescriptor.authMode == Access::AuthMode::kCase) - { - scopedNodeId = ScopedNodeId(subjectDescriptor.subject, subjectDescriptor.fabricIndex); - } - - if (GetOriginatorScopedNodeId(endpoint) != scopedNodeId) + if (!InAtomicWrite(subjectDescriptor, endpoint)) { ChipLogError(Zcl, "Another node is editing presets. Server is busy. Try again later"); return CHIP_IM_GLOBAL_STATUS(Busy); @@ -889,14 +869,7 @@ CHIP_ERROR ThermostatAttrAccess::Write(const ConcreteDataAttributePath & aPath, while (iter.Next()) { const PresetStruct::Type & preset = iter.GetValue(); - if (IsValidPresetEntry(preset)) - { - ReturnErrorOnFailure(delegate->AppendToPendingPresetList(preset)); - } - else - { - return CHIP_IM_GLOBAL_STATUS(ConstraintError); - } + ReturnErrorOnFailure(AppendPendingPreset(delegate, preset)); } return iter.GetStatus(); } @@ -906,11 +879,7 @@ CHIP_ERROR ThermostatAttrAccess::Write(const ConcreteDataAttributePath & aPath, { PresetStruct::Type preset; ReturnErrorOnFailure(aDecoder.Decode(preset)); - if (IsValidPresetEntry(preset)) - { - return delegate->AppendToPendingPresetList(preset); - } - return CHIP_IM_GLOBAL_STATUS(ConstraintError); + return AppendPendingPreset(delegate, preset); } } break; @@ -918,6 +887,36 @@ CHIP_ERROR ThermostatAttrAccess::Write(const ConcreteDataAttributePath & aPath, return CHIP_ERROR_NOT_IMPLEMENTED; } break; + } + + // This is not an atomic attribute, so check to make sure we don't have an atomic write going for this client + if (InAtomicWrite(subjectDescriptor, endpoint)) + { + ChipLogError(Zcl, "Can not write to non-atomic attributes during atomic write"); + return CHIP_IM_GLOBAL_STATUS(InvalidInState); + } + + uint32_t ourFeatureMap; + bool localTemperatureNotExposedSupported = (FeatureMap::Get(aPath.mEndpointId, &ourFeatureMap) == imcode::Success) && + ((ourFeatureMap & to_underlying(Feature::kLocalTemperatureNotExposed)) != 0); + + switch (aPath.mAttributeId) + { + case RemoteSensing::Id: + if (localTemperatureNotExposedSupported) + { + uint8_t valueRemoteSensing; + ReturnErrorOnFailure(aDecoder.Decode(valueRemoteSensing)); + if (valueRemoteSensing & 0x01) // If setting bit 1 (LocalTemperature RemoteSensing bit) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + imcode status = RemoteSensing::Set(aPath.mEndpointId, valueRemoteSensing); + StatusIB statusIB(status); + return statusIB.ToChipError(); + } + break; + default: // return CHIP_NO_ERROR and just write to the attribute store in default break; } @@ -925,6 +924,60 @@ CHIP_ERROR ThermostatAttrAccess::Write(const ConcreteDataAttributePath & aPath, return CHIP_NO_ERROR; } +CHIP_ERROR ThermostatAttrAccess::AppendPendingPreset(Delegate * delegate, const PresetStruct::Type & preset) +{ + if (!IsValidPresetEntry(preset)) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + if (preset.presetHandle.IsNull()) + { + if (IsBuiltIn(preset)) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + } + else + { + auto & presetHandle = preset.presetHandle.Value(); + + // Per spec we need to check that: + // (a) There is an existing non-pending preset with this handle. + PresetStructWithOwnedMembers matchingPreset; + if (!GetMatchingPresetInPresets(delegate, preset, matchingPreset)) + { + return CHIP_IM_GLOBAL_STATUS(NotFound); + } + + // (b) There is no existing pending preset with this handle. + if (CountPresetsInPendingListWithPresetHandle(delegate, presetHandle) > 0) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + // (c)/(d) The built-in fields do not have a mismatch. + // TODO: What's the story with nullability on the BuiltIn field? + if (!preset.builtIn.IsNull() && !matchingPreset.GetBuiltIn().IsNull() && + preset.builtIn.Value() != matchingPreset.GetBuiltIn().Value()) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + } + + if (!PresetScenarioExistsInPresetTypes(delegate, preset.presetScenario)) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + if (preset.name.HasValue() && !PresetTypeSupportsNames(delegate, preset.presetScenario)) + { + return CHIP_IM_GLOBAL_STATUS(ConstraintError); + } + + return delegate->AppendToPendingPresetList(preset); +} + } // namespace Thermostat } // namespace Clusters } // namespace app @@ -1244,16 +1297,16 @@ bool emberAfThermostatClusterSetWeeklyScheduleCallback(app::CommandHandler * com } bool emberAfThermostatClusterSetActiveScheduleRequestCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Thermostat::Commands::SetActiveScheduleRequest::DecodableType & commandData) + CommandHandler * commandObj, const ConcreteCommandPath & commandPath, + const Clusters::Thermostat::Commands::SetActiveScheduleRequest::DecodableType & commandData) { // TODO return false; } bool emberAfThermostatClusterSetActivePresetRequestCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Thermostat::Commands::SetActivePresetRequest::DecodableType & commandData) + CommandHandler * commandObj, const ConcreteCommandPath & commandPath, + const Clusters::Thermostat::Commands::SetActivePresetRequest::DecodableType & commandData) { EndpointId endpoint = commandPath.mEndpointId; Delegate * delegate = GetDelegate(endpoint); @@ -1287,112 +1340,123 @@ bool emberAfThermostatClusterSetActivePresetRequestCallback( return true; } -bool emberAfThermostatClusterStartPresetsSchedulesEditRequestCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Thermostat::Commands::StartPresetsSchedulesEditRequest::DecodableType & commandData) +bool validAtomicAttributes(const Commands::AtomicRequest::DecodableType & commandData, bool requireBoth) { - ScopedNodeId sourceNodeId = GetSourceScopedNodeId(commandObj); - - EndpointId endpoint = commandPath.mEndpointId; + auto attributeIdsIter = commandData.attributeRequests.begin(); + bool requestedPresets = false, requestedSchedules = false; + while (attributeIdsIter.Next()) + { + auto & attributeId = attributeIdsIter.GetValue(); - // If the presets are editable and the scoped node id of the client sending StartPresetsSchedulesEditRequest command - // is not the same as the one that previously originated a StartPresetsSchedulesEditRequest command, return BUSY. - if (gThermostatAttrAccess.GetPresetsEditable(endpoint) && - (gThermostatAttrAccess.GetOriginatorScopedNodeId(endpoint) != sourceNodeId)) + switch (attributeId) + { + case Presets::Id: + if (requestedPresets) // Double-requesting an attribute is invalid + { + return false; + } + requestedPresets = true; + break; + case Schedules::Id: + if (requestedSchedules) // Double-requesting an attribute is invalid + { + return false; + } + requestedSchedules = true; + break; + default: + return false; + } + } + if (attributeIdsIter.GetStatus() != CHIP_NO_ERROR) { - commandObj->AddStatus(commandPath, imcode::Busy); - return true; + return false; } - - // If presets are editable and the scoped node id of the client sending StartPresetsSchedulesEditRequest command - // is the same as the one that previously originated a StartPresetsSchedulesEditRequest command, extend the timer. - if (gThermostatAttrAccess.GetPresetsEditable(endpoint)) + if (requireBoth) { - ExtendTimer(endpoint, commandData.timeoutSeconds); - commandObj->AddStatus(commandPath, imcode::Success); - return true; + return (requestedPresets && requestedSchedules); } + // If the atomic request doesn't contain at least one of these attributes, it's invalid + return (requestedPresets || requestedSchedules); +} - // Set presets editable to true and the scoped originator node id to the source scoped node id, and start a timer with the - // timeout in seconds passed in the command args. Return success. - gThermostatAttrAccess.SetPresetsEditable(endpoint, true); - gThermostatAttrAccess.SetOriginatorScopedNodeId(endpoint, sourceNodeId); - ScheduleTimer(endpoint, commandData.timeoutSeconds); - commandObj->AddStatus(commandPath, imcode::Success); - return true; +void sendAtomicResponse(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, imcode status, imcode presetsStatus, + imcode schedulesStatus, Optional timeout = NullOptional) +{ + Commands::AtomicResponse::Type response; + Globals::Structs::AtomicAttributeStatusStruct::Type attributeStatus[] = { + { .attributeID = Presets::Id, .statusCode = to_underlying(presetsStatus) }, + { .attributeID = Schedules::Id, .statusCode = to_underlying(schedulesStatus) } + }; + response.statusCode = to_underlying(status); + response.attributeStatus = attributeStatus; + response.timeout = timeout; + commandObj->AddResponse(commandPath, response); } -bool emberAfThermostatClusterCancelPresetsSchedulesEditRequestCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Thermostat::Commands::CancelPresetsSchedulesEditRequest::DecodableType & commandData) +void handleAtomicBegin(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, + const Commands::AtomicRequest::DecodableType & commandData) { EndpointId endpoint = commandPath.mEndpointId; - // If presets are not editable, return INVALID_IN_STATE. - if (!gThermostatAttrAccess.GetPresetsEditable(endpoint)) + Delegate * delegate = GetDelegate(endpoint); + + if (delegate == nullptr) { + ChipLogError(Zcl, "Delegate is null"); commandObj->AddStatus(commandPath, imcode::InvalidInState); - return true; + return; } - ScopedNodeId sourceNodeId = GetSourceScopedNodeId(commandObj); - - // If the node id sending the CancelPresetsSchedulesRequest command is not the same as the one which send the - // previous StartPresetsSchedulesEditRequest, return UNSUPPORTED_ACCESS. - if (gThermostatAttrAccess.GetOriginatorScopedNodeId(endpoint) != sourceNodeId) + if (gThermostatAttrAccess.InAtomicWrite(commandObj, endpoint)) { - commandObj->AddStatus(commandPath, imcode::UnsupportedAccess); - return true; + // This client already has an open atomic write + commandObj->AddStatus(commandPath, imcode::InvalidInState); + return; } - Delegate * delegate = GetDelegate(endpoint); - - if (delegate == nullptr) + if (!commandData.timeout.HasValue()) { - ChipLogError(Zcl, "Delegate is null"); - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::InvalidInState); + commandObj->AddStatus(commandPath, imcode::InvalidCommand); + return; } - // Clear the timer, discard the changes and set PresetsEditable to false. - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::Success); -} - -bool emberAfThermostatClusterCommitPresetsSchedulesRequestCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Thermostat::Commands::CommitPresetsSchedulesRequest::DecodableType & commandData) -{ - EndpointId endpoint = commandPath.mEndpointId; - Delegate * delegate = GetDelegate(endpoint); + auto timeout = commandData.timeout.Value(); - if (delegate == nullptr) + if (!validAtomicAttributes(commandData, false)) { - ChipLogError(Zcl, "Delegate is null"); - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::InvalidInState); + commandObj->AddStatus(commandPath, imcode::InvalidCommand); + return; } - // If presets are not editable, return INVALID_IN_STATE. - if (!gThermostatAttrAccess.GetPresetsEditable(endpoint)) + if (gThermostatAttrAccess.InAtomicWrite(endpoint)) { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::InvalidInState); + sendAtomicResponse(commandObj, commandPath, imcode::Failure, imcode::Busy, imcode::Busy); + return; } - ScopedNodeId sourceNodeId = GetSourceScopedNodeId(commandObj); + // This is a valid request to open an atomic write. Tell the delegate it + // needs to keep track of a pending preset list now. + delegate->InitializePendingPresets(); - // If the node id sending the CommitPresetsSchedulesRequest command is not the same as the one which send the - // StartPresetsSchedulesEditRequest, return UNSUPPORTED_ACCESS. - if (gThermostatAttrAccess.GetOriginatorScopedNodeId(endpoint) != sourceNodeId) - { - commandObj->AddStatus(commandPath, imcode::UnsupportedAccess); - return true; - } + uint16_t maxTimeout = 5000; + timeout = std::min(timeout, maxTimeout); + + ScheduleTimer(endpoint, System::Clock::Milliseconds16(timeout)); + gThermostatAttrAccess.SetAtomicWrite(endpoint, true); + gThermostatAttrAccess.SetAtomicWriteScopedNodeId(endpoint, GetSourceScopedNodeId(commandObj)); + sendAtomicResponse(commandObj, commandPath, imcode::Success, imcode::Success, imcode::Success, MakeOptional(timeout)); +} - PresetStructWithOwnedMembers preset; +imcode commitPresets(Delegate * delegate, EndpointId endpoint) +{ CHIP_ERROR err = CHIP_NO_ERROR; // For each preset in the presets attribute, check that the matching preset in the pending presets list does not // violate any spec constraints. for (uint8_t i = 0; true; i++) { + PresetStructWithOwnedMembers preset; err = delegate->GetPresetAtIndex(i, preset); if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) @@ -1405,7 +1469,7 @@ bool emberAfThermostatClusterCommitPresetsSchedulesRequestCallback( "emberAfThermostatClusterCommitPresetsSchedulesRequestCallback: GetPresetAtIndex failed with error " "%" CHIP_ERROR_FORMAT, err.Format()); - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::InvalidInState); + return imcode::InvalidInState; } bool found = MatchingPendingPresetExists(delegate, preset); @@ -1414,7 +1478,7 @@ bool emberAfThermostatClusterCommitPresetsSchedulesRequestCallback( // CONSTRAINT_ERROR. if (IsBuiltIn(preset) && !found) { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::ConstraintError); + return imcode::ConstraintError; } } @@ -1428,7 +1492,7 @@ bool emberAfThermostatClusterCommitPresetsSchedulesRequestCallback( if (err != CHIP_NO_ERROR) { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::InvalidInState); + return imcode::InvalidInState; } if (!activePresetHandle.empty()) @@ -1436,7 +1500,7 @@ bool emberAfThermostatClusterCommitPresetsSchedulesRequestCallback( uint8_t count = CountPresetsInPendingListWithPresetHandle(delegate, activePresetHandle); if (count == 0) { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::InvalidInState); + return imcode::InvalidInState; } } @@ -1456,67 +1520,11 @@ bool emberAfThermostatClusterCommitPresetsSchedulesRequestCallback( "emberAfThermostatClusterCommitPresetsSchedulesRequestCallback: GetPendingPresetAtIndex failed with error " "%" CHIP_ERROR_FORMAT, err.Format()); - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::InvalidInState); - } - - bool isPendingPresetWithNullPresetHandle = pendingPreset.GetPresetHandle().IsNull(); - - // If the preset handle is null and the built in field is set to true, return CONSTRAINT_ERROR. - if (isPendingPresetWithNullPresetHandle && IsBuiltIn(pendingPreset)) - { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::ConstraintError); - } - - bool foundMatchingPresetInPresets = false; - PresetStructWithOwnedMembers matchingPreset; - if (!isPendingPresetWithNullPresetHandle) - { - foundMatchingPresetInPresets = GetMatchingPresetInPresets(delegate, pendingPreset, matchingPreset); - - // If the presetHandle for the pending preset is not null and a matching preset is not found in the - // presets attribute list, return NOT_FOUND. - if (!foundMatchingPresetInPresets) - { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::NotFound); - } - - // Find the number of presets in the pending preset list that match the preset handle. If there are duplicate - // entries, return CONSTRAINT_ERROR. - uint8_t count = CountPresetsInPendingListWithPresetHandle(delegate, pendingPreset.GetPresetHandle().Value()); - if (count > 1) - { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::ConstraintError); - } - } - - // If the preset is found in the presets attribute list and the preset is builtIn in the pending presets list - // but not in the presets attribute list, return UNSUPPORTED_ACCESS. - if (foundMatchingPresetInPresets && (IsBuiltIn(pendingPreset) && !IsBuiltIn(matchingPreset))) - { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::UnsupportedAccess); - } - - // If the preset is found in the presets attribute list and the preset is builtIn in the presets attribute - // but not in the pending presets list, return UNSUPPORTED_ACCESS. - if (foundMatchingPresetInPresets && (!IsBuiltIn(pendingPreset) && IsBuiltIn(matchingPreset))) - { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::UnsupportedAccess); - } - - // If the presetScenario is not found in the preset types, return CONSTRAINT_ERROR. - PresetScenarioEnum presetScenario = pendingPreset.GetPresetScenario(); - if (!PresetScenarioExistsInPresetTypes(delegate, presetScenario)) - { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::ConstraintError); - } - - // If the preset type for the preset scenario does not support names and a name is specified, return CONSTRAINT_ERROR. - if (!PresetTypeSupportsNames(delegate, presetScenario) && pendingPreset.GetName().HasValue()) - { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::ConstraintError); + return imcode::InvalidInState; } // Enforce the Setpoint Limits for both the cooling and heating setpoints in the pending preset. + // TODO: This code does not work, because it's modifying our temporary copy. Optional coolingSetpointValue = pendingPreset.GetCoolingSetpoint(); if (coolingSetpointValue.HasValue()) { @@ -1537,14 +1545,14 @@ bool emberAfThermostatClusterCommitPresetsSchedulesRequestCallback( if (numberOfPresetsSupported == 0) { ChipLogError(Zcl, "emberAfThermostatClusterCommitPresetsSchedulesRequestCallback: Failed to get NumberOfPresets"); - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::InvalidInState); + return imcode::InvalidInState; } // If the expected length of the presets attribute with the applied changes exceeds the total number of presets supported, // return RESOURCE_EXHAUSTED. Note that the changes are not yet applied. if (numberOfPresetsSupported > 0 && totalCount > numberOfPresetsSupported) { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::ResourceExhausted); + return imcode::ResourceExhausted; } // TODO: Check if the number of presets for each presetScenario exceeds the max number of presets supported for that @@ -1555,10 +1563,98 @@ bool emberAfThermostatClusterCommitPresetsSchedulesRequestCallback( if (err != CHIP_NO_ERROR) { - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::InvalidInState); + return imcode::InvalidInState; + } + + return imcode::Success; +} + +void handleAtomicCommit(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, + const Commands::AtomicRequest::DecodableType & commandData) +{ + if (!validAtomicAttributes(commandData, true)) + { + commandObj->AddStatus(commandPath, imcode::InvalidCommand); + return; + } + EndpointId endpoint = commandPath.mEndpointId; + bool inAtomicWrite = gThermostatAttrAccess.InAtomicWrite(commandObj, endpoint); + if (!inAtomicWrite) + { + commandObj->AddStatus(commandPath, imcode::InvalidInState); + return; + } + + Delegate * delegate = GetDelegate(endpoint); + + if (delegate == nullptr) + { + ChipLogError(Zcl, "Delegate is null"); + commandObj->AddStatus(commandPath, imcode::InvalidInState); + return; + } + + auto presetsStatus = commitPresets(delegate, endpoint); + // TODO: copy over schedules code + auto schedulesStatus = imcode::Success; + resetAtomicWrite(delegate, endpoint); + imcode status = (presetsStatus == imcode::Success && schedulesStatus == imcode::Success) ? imcode::Success : imcode::Failure; + sendAtomicResponse(commandObj, commandPath, status, presetsStatus, schedulesStatus); +} + +void handleAtomicRollback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, + const Commands::AtomicRequest::DecodableType & commandData) +{ + if (!validAtomicAttributes(commandData, true)) + { + commandObj->AddStatus(commandPath, imcode::InvalidCommand); + return; + } + EndpointId endpoint = commandPath.mEndpointId; + bool inAtomicWrite = gThermostatAttrAccess.InAtomicWrite(commandObj, endpoint); + if (!inAtomicWrite) + { + commandObj->AddStatus(commandPath, imcode::InvalidInState); + return; + } + + Delegate * delegate = GetDelegate(endpoint); + + if (delegate == nullptr) + { + ChipLogError(Zcl, "Delegate is null"); + commandObj->AddStatus(commandPath, imcode::InvalidInState); + return; + } + resetAtomicWrite(delegate, endpoint); + sendAtomicResponse(commandObj, commandPath, imcode::Success, imcode::Success, imcode::Success); +} + +bool emberAfThermostatClusterAtomicRequestCallback(CommandHandler * commandObj, const ConcreteCommandPath & commandPath, + const Clusters::Thermostat::Commands::AtomicRequest::DecodableType & commandData) +{ + auto & requestType = commandData.requestType; + + // If we've gotten this far, then the client has manage permission to call AtomicRequest, which is also the + // privilege necessary to write to the atomic attributes, so no need to check + + switch (requestType) + { + case Globals::AtomicRequestTypeEnum::kBeginWrite: + handleAtomicBegin(commandObj, commandPath, commandData); + return true; + case Globals::AtomicRequestTypeEnum::kCommitWrite: + handleAtomicCommit(commandObj, commandPath, commandData); + return true; + case Globals::AtomicRequestTypeEnum::kRollbackWrite: + handleAtomicRollback(commandObj, commandPath, commandData); + return true; + case Globals::AtomicRequestTypeEnum::kUnknownEnumValue: + commandObj->AddStatus(commandPath, imcode::InvalidCommand); + return true; } - return SendResponseAndCleanUp(delegate, endpoint, commandObj, commandPath, imcode::Success); + return false; } bool emberAfThermostatClusterSetpointRaiseLowerCallback(app::CommandHandler * commandObj, diff --git a/src/app/clusters/thermostat-server/thermostat-server.h b/src/app/clusters/thermostat-server/thermostat-server.h index 955ab9e5c5a777..306a2a625c57b6 100644 --- a/src/app/clusters/thermostat-server/thermostat-server.h +++ b/src/app/clusters/thermostat-server/thermostat-server.h @@ -27,6 +27,7 @@ #include "thermostat-delegate.h" #include +#include namespace chip { namespace app { @@ -48,45 +49,66 @@ class ThermostatAttrAccess : public chip::app::AttributeAccessInterface CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, chip::app::AttributeValueDecoder & aDecoder) override; /** - * @brief Sets the scoped node id of the originator that send the last successful - * StartPresetsSchedulesEditRequest for the given endpoint. + * @brief Sets the scoped node id of the originator that sent the last successful + * AtomicRequest of type BeginWrite for the given endpoint. * * @param[in] endpoint The endpoint. * @param[in] originatorNodeId The originator scoped node id. */ - void SetOriginatorScopedNodeId(EndpointId endpoint, ScopedNodeId originatorNodeId); + void SetAtomicWriteScopedNodeId(EndpointId endpoint, ScopedNodeId originatorNodeId); /** - * @brief Gets the scoped node id of the originator that send the last successful - * StartPresetsSchedulesEditRequest for the given endpoint. + * @brief Gets the scoped node id of the originator that sent the last successful + * AtomicRequest of type BeginWrite for the given endpoint. * * @param[in] endpoint The endpoint. * * @return the scoped node id for the given endpoint if set. Otherwise returns ScopedNodeId(). */ - ScopedNodeId GetOriginatorScopedNodeId(EndpointId endpoint); + ScopedNodeId GetAtomicWriteScopedNodeId(EndpointId endpoint); /** - * @brief Sets the presets editable flag for the given endpoint + * @brief Sets whether an atomic write is in progress for the given endpoint * * @param[in] endpoint The endpoint. - * @param[in] presetEditable The value of the presets editable. + * @param[in] inProgress Whether or not an atomic write is in progress. */ - void SetPresetsEditable(EndpointId endpoint, bool presetEditable); + void SetAtomicWrite(EndpointId endpoint, bool inProgress); /** - * @brief Gets the prests editable flag value for the given endpoint + * @brief Gets whether an atomic write is in progress for the given endpoint * * @param[in] endpoint The endpoint. * - * @return the presets editable flag value for the given endpoint if set. Otherwise returns false. + * @return Whether an atomic write is in progress for the given endpoint */ - bool GetPresetsEditable(EndpointId endpoint); + bool InAtomicWrite(EndpointId endpoint); + + /** + * @brief Gets whether an atomic write is in progress for the given endpoint + * + * @param[in] subjectDescriptor The subject descriptor. + * @param[in] endpoint The endpoint. + * + * @return Whether an atomic write is in progress for the given endpoint + */ + bool InAtomicWrite(const Access::SubjectDescriptor & subjectDescriptor, EndpointId endpoint); + + /** + * @brief Gets whether an atomic write is in progress for the given endpoint + * + * @param[in] commandObj The command handler. + * @param[in] endpoint The endpoint. + * + * @return Whether an atomic write is in progress for the given endpoint + */ + bool InAtomicWrite(CommandHandler * commandObj, EndpointId endpoint); private: - ScopedNodeId mPresetEditRequestOriginatorNodeIds[kThermostatEndpointCount]; + CHIP_ERROR AppendPendingPreset(Delegate * delegate, const Structs::PresetStruct::Type & preset); - bool mPresetsEditables[kThermostatEndpointCount]; + ScopedNodeId mAtomicWriteNodeIds[kThermostatEndpointCount]; + bool mAtomicWriteState[kThermostatEndpointCount]; }; /** diff --git a/src/app/tests/suites/certification/PICS.yaml b/src/app/tests/suites/certification/PICS.yaml index 8a3e1fce94326f..9d8011ceee2172 100644 --- a/src/app/tests/suites/certification/PICS.yaml +++ b/src/app/tests/suites/certification/PICS.yaml @@ -6491,8 +6491,8 @@ PICS: - label: "Does the device implement the Presets attribute?" id: TSTAT.S.A0050 - - label: "Does the device implement the PresetsSchedulesEditable attribute?" - id: TSTAT.S.A0052 + - label: "Does the device implement the Schedules attribute?" + id: TSTAT.S.A0051 # # server / commandsReceived @@ -6523,19 +6523,9 @@ PICS: id: TSTAT.S.C06.Rsp - label: - "Does the device implement receiving the - StartPresetsSchedulesEditRequest command?" - id: TSTAT.S.C07.Rsp - - - label: - "Does the device implement receiving the - CancelPresetsSchedulesEditRequest command?" - id: TSTAT.S.C08.Rsp - - - label: - "Does the device implement receiving the CommitPresetsSchedulesRequest - command?" - id: TSTAT.S.C09.Rsp + "Does the device implement receiving the AtomicRequest command for + Thermostat?" + id: TSTAT.S.CFE.Rsp # # server / commandsGenerated @@ -6550,6 +6540,9 @@ PICS: command?" id: TSTAT.S.C01.Tx + - label: "Does the device implement sending the AtomicResponse command?" + id: TSTAT.S.CFD.Tx + # # server / features # @@ -6622,20 +6615,8 @@ PICS: "Does the device implement sending the SetActivePresetRequest command?" id: TSTAT.C.C06.Tx - - label: - "Does the device implement sending the - StartPresetsSchedulesEditRequest command?" - id: TSTAT.C.C07.Tx - - - label: - "Does the device implement sending the - CancelPresetsSchedulesEditRequest command?" - id: TSTAT.C.C08.Tx - - - label: - "Does the device implement sending the CommitPresetsSchedulesRequest - command?" - id: TSTAT.C.C09.Tx + - label: "Does the device implement sending the AtomicRequest command?" + id: TSTAT.C.CFE.Tx # # client / manually diff --git a/src/app/tests/suites/certification/Test_TC_TSTAT_1_1.yaml b/src/app/tests/suites/certification/Test_TC_TSTAT_1_1.yaml index 40a65d7952d608..fe6b89ae930517 100644 --- a/src/app/tests/suites/certification/Test_TC_TSTAT_1_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_TSTAT_1_1.yaml @@ -624,7 +624,7 @@ tests: response: constraints: type: list - contains: [6, 7, 8, 9] + contains: [254] - label: "Step 7a: TH reads from the DUT the GeneratedCommandList attribute." @@ -632,7 +632,7 @@ tests: command: "readAttribute" attribute: "GeneratedCommandList" response: - value: [] + value: [0xFD] # AtomicResponse constraints: type: list diff --git a/src/app/tests/suites/certification/Test_TC_TSTAT_4_1.yaml b/src/app/tests/suites/certification/Test_TC_TSTAT_4_1.yaml index 9785c8b1bda0c1..aa12c7bec5e6f0 100644 --- a/src/app/tests/suites/certification/Test_TC_TSTAT_4_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_TSTAT_4_1.yaml @@ -62,14 +62,12 @@ tests: response: saveAs: PresetsValue - - label: - "Saving value for comparision in step 6 read PresetsSchedulesEditable - attribute" - PICS: TSTAT.S.A0052 + - label: "Saving value for comparision in step 6 read Schedules attribute" + PICS: TSTAT.S.A0051 command: "readAttribute" - attribute: "PresetsSchedulesEditable" + attribute: "Schedules" response: - saveAs: PresetsSchedulesEditableValue + saveAs: SchedulesValue - label: "Step 2: TH reads the PresetTypes attribute from the DUT" PICS: TSTAT.S.F08 & TSTAT.S.A0048 @@ -103,11 +101,10 @@ tests: constraints: type: list - - label: - "Step 6: TH reads the PresetsSchedulesEditable attribute from the DUT" - PICS: TSTAT.S.F08 & TSTAT.S.A0052 + - label: "Step 6: TH reads the Schedules attribute from the DUT" + PICS: TSTAT.S.F07 & TSTAT.S.A0051 command: "readAttribute" - attribute: "PresetsSchedulesEditable" + attribute: "Schedules" response: constraints: - type: boolean + type: list diff --git a/src/app/tests/suites/certification/ci-pics-values b/src/app/tests/suites/certification/ci-pics-values index a8601fbd27d3ef..70a0e79760be3a 100644 --- a/src/app/tests/suites/certification/ci-pics-values +++ b/src/app/tests/suites/certification/ci-pics-values @@ -1987,7 +1987,7 @@ TSTAT.S.A0048=1 TSTAT.S.A004a=1 TSTAT.S.A004e=1 TSTAT.S.A0050=1 -TSTAT.S.A0052=1 +TSTAT.S.A0051=1 TSTAT.S.M.MinSetpointDeadBandWritable=1 TSTAT.S.M.HVACSystemTypeConfigurationWritable=0 @@ -1999,9 +1999,8 @@ TSTAT.S.C02.Rsp=0 TSTAT.S.C03.Rsp=0 TSTAT.S.C04.Rsp=0 TSTAT.S.C06.Rsp=1 -TSTAT.S.C07.Rsp=1 -TSTAT.S.C08.Rsp=1 -TSTAT.S.C09.Rsp=1 +TSTAT.S.CFE.Rsp=1 +TSTAT.S.CFD.Tx=1 # Client TSTAT.C=0 @@ -2017,13 +2016,11 @@ TSTAT.C.C03.Tx=0 TSTAT.S.C00.Tx=0 TSTAT.S.C01.Tx=0 TSTAT.C.C06.Tx=1 -TSTAT.C.C07.Tx=1 -TSTAT.C.C08.Tx=1 -TSTAT.C.C09.Tx=1 +TSTAT.C.CFE.Tx=1 # Client Commands TSTAT.C.C00.Tx=1 -TSTAT.C.C04.Tx=0 +TSTAT.C.C04.Tx=1 # Access Control cluster ACL.S=1 diff --git a/src/app/util/attribute-table.cpp b/src/app/util/attribute-table.cpp index 303b234ff93862..211d2a19123dbd 100644 --- a/src/app/util/attribute-table.cpp +++ b/src/app/util/attribute-table.cpp @@ -44,7 +44,8 @@ namespace { // Zigbee spec says types between signed 8 bit and signed 64 bit bool emberAfIsTypeSigned(EmberAfAttributeType dataType) { - return (dataType >= ZCL_INT8S_ATTRIBUTE_TYPE && dataType <= ZCL_INT64S_ATTRIBUTE_TYPE); + return (dataType >= ZCL_INT8S_ATTRIBUTE_TYPE && dataType <= ZCL_INT64S_ATTRIBUTE_TYPE) || + dataType == ZCL_TEMPERATURE_ATTRIBUTE_TYPE; } /** diff --git a/src/app/zap-templates/zcl/data-model/all.xml b/src/app/zap-templates/zcl/data-model/all.xml index 2a2f73ccfc1709..265e80c079e161 100644 --- a/src/app/zap-templates/zcl/data-model/all.xml +++ b/src/app/zap-templates/zcl/data-model/all.xml @@ -47,6 +47,8 @@ + + diff --git a/src/app/zap-templates/zcl/data-model/chip/global-bitmaps.xml b/src/app/zap-templates/zcl/data-model/chip/global-bitmaps.xml new file mode 100644 index 00000000000000..fc70c0bf5143a9 --- /dev/null +++ b/src/app/zap-templates/zcl/data-model/chip/global-bitmaps.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + diff --git a/src/app/zap-templates/zcl/data-model/chip/global-enums.xml b/src/app/zap-templates/zcl/data-model/chip/global-enums.xml new file mode 100644 index 00000000000000..54f38c1b6933e8 --- /dev/null +++ b/src/app/zap-templates/zcl/data-model/chip/global-enums.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app/zap-templates/zcl/data-model/chip/global-structs.xml b/src/app/zap-templates/zcl/data-model/chip/global-structs.xml index 4e1ce5f3827298..743fdf366b724b 100644 --- a/src/app/zap-templates/zcl/data-model/chip/global-structs.xml +++ b/src/app/zap-templates/zcl/data-model/chip/global-structs.xml @@ -17,6 +17,12 @@ limitations under the License. + + + + + + @@ -27,17 +33,7 @@ limitations under the License. These are test global items (no cluster attached) for testing only. Their usage is defined for UnitTestCluster only. --> - - - - - - - - - - - + diff --git a/src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml index f731b66c6a1422..546692b1a42030 100644 --- a/src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/thermostat-cluster.xml @@ -16,8 +16,6 @@ limitations under the License. --> - - @@ -35,6 +33,11 @@ limitations under the License. + + + + + @@ -145,7 +148,7 @@ limitations under the License. - + @@ -194,7 +197,6 @@ limitations under the License. - @@ -207,7 +209,7 @@ limitations under the License. - + @@ -219,20 +221,19 @@ limitations under the License. - - + - + - + @@ -244,13 +245,13 @@ limitations under the License. - + - + @@ -265,15 +266,14 @@ limitations under the License. THERMOSTAT_CLUSTER true true - - + - + @@ -281,7 +281,7 @@ limitations under the License. - + @@ -304,59 +304,52 @@ limitations under the License. - + - - - - + - - - LocalTemperature - OutdoorTemperature - Occupancy - - AbsMinHeatSetpointLimit - AbsMaxHeatSetpointLimit - AbsMinCoolSetpointLimit - AbsMaxCoolSetpointLimit - PICoolingDemand - PIHeatingDemand - + LocalTemperature + OutdoorTemperature + Occupancy + AbsMinHeatSetpointLimit + AbsMaxHeatSetpointLimit + AbsMinCoolSetpointLimit + AbsMaxCoolSetpointLimit + PICoolingDemand + PIHeatingDemand + HVACSystemTypeConfiguration - LocalTemperatureCalibration - OccupiedCoolingSetpoint - OccupiedHeatingSetpoint - UnoccupiedCoolingSetpoint - UnoccupiedHeatingSetpoint - + OccupiedCoolingSetpoint + OccupiedHeatingSetpoint + UnoccupiedCoolingSetpoint + UnoccupiedHeatingSetpoint + MinHeatSetpointLimit - + MaxHeatSetpointLimit - + MinCoolSetpointLimit - + MaxCoolSetpointLimit - + MinSetpointDeadBand @@ -364,23 +357,23 @@ limitations under the License. RemoteSensing - + ControlSequenceOfOperation - + SystemMode - ThermostatRunningMode - StartOfWeek - NumberOfWeeklyTransitions - NumberOfDailyTransitions + ThermostatRunningMode + StartOfWeek + NumberOfWeeklyTransitions + NumberOfDailyTransitions TemperatureSetpointHold - + TemperatureSetpointHoldDuration @@ -388,23 +381,23 @@ limitations under the License. ThermostatProgrammingOperationMode - ThermostatRunningState - SetpointChangeSource - SetpointChangeAmount - SetpointChangeSourceTimestamp - + ThermostatRunningState + SetpointChangeSource + SetpointChangeAmount + SetpointChangeSourceTimestamp + OccupiedSetback - OccupiedSetbackMin - OccupiedSetbackMax - + OccupiedSetbackMin + OccupiedSetbackMax + UnoccupiedSetback - UnoccupiedSetbackMin - UnoccupiedSetbackMax - + UnoccupiedSetbackMin + UnoccupiedSetbackMax + EmergencyHeatDelta @@ -412,7 +405,7 @@ limitations under the License. ACType - + ACCapacity @@ -424,7 +417,7 @@ limitations under the License. ACCompressorType - + ACErrorCode @@ -432,93 +425,88 @@ limitations under the License. ACLouverPosition - ACCoilTemperature - + ACCoilTemperature + ACCapacityformat - PresetTypes - ScheduleTypes - NumberOfPresets - NumberOfSchedules - NumberOfScheduleTransitions - NumberOfScheduleTransitionPerDay - ActivePresetHandle - ActiveScheduleHandle - + PresetTypes + ScheduleTypes + NumberOfPresets + NumberOfSchedules + NumberOfScheduleTransitions + NumberOfScheduleTransitionPerDay + ActivePresetHandle + ActiveScheduleHandle + Presets - + Schedules - PresetsSchedulesEditable - SetpointHoldExpiryTimestamp - + SetpointHoldExpiryTimestamp - - - Command description for SetpointRaiseLower - - - + Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. + + + - - Command description for SetWeeklySchedule - + This command is used to update the thermostat weekly setpoint schedule from a management system. - - - - + + + + + - - Command description for GetWeeklySchedule - - - + The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. + + + - This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. + This command is used to clear the weekly schedule. - + + - This command is used to set the active schedule. - + Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. + + - This command is used to set the active preset. - - - - This command is used to start editing the presets and schedules. - - - - - This command is used to cancel editing presets and schedules. - - - - This command is used to notify the server that all edits are done and should be committed. - + ID + + + This command has the same payload format as the Set Weekly Schedule. + + + + + - - - The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. - - - - - + + Returns the status of an atomic write + + + + + + + Begins, Commits or Cancels an atomic write + + + + - \ No newline at end of file + diff --git a/src/app/zap-templates/zcl/zcl-with-test-extensions.json b/src/app/zap-templates/zcl/zcl-with-test-extensions.json index 3a19eba34b745a..4de0247c17d86a 100644 --- a/src/app/zap-templates/zcl/zcl-with-test-extensions.json +++ b/src/app/zap-templates/zcl/zcl-with-test-extensions.json @@ -63,6 +63,8 @@ "general-commissioning-cluster.xml", "general-diagnostics-cluster.xml", "global-attributes.xml", + "global-bitmaps.xml", + "global-enums.xml", "global-structs.xml", "groups-cluster.xml", "group-key-mgmt-cluster.xml", diff --git a/src/app/zap-templates/zcl/zcl.json b/src/app/zap-templates/zcl/zcl.json index 4714e240bbf3a3..3a17b76c4723b9 100644 --- a/src/app/zap-templates/zcl/zcl.json +++ b/src/app/zap-templates/zcl/zcl.json @@ -61,6 +61,8 @@ "general-commissioning-cluster.xml", "general-diagnostics-cluster.xml", "global-attributes.xml", + "global-bitmaps.xml", + "global-enums.xml", "global-structs.xml", "groups-cluster.xml", "group-key-mgmt-cluster.xml", diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index c32f6412acdee0..2954d22de36479 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -99,6 +99,12 @@ enum AreaTypeTag : enum8 { kWorkshop = 94; } +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + enum FloorSurfaceTag : enum8 { kCarpet = 0; kCeramic = 1; @@ -220,6 +226,11 @@ struct LocationDescriptorStruct { nullable AreaTypeTag areaType = 2; } +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + /** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ cluster Identify = 3 { revision 4; @@ -6646,7 +6657,7 @@ cluster PumpConfigurationAndControl = 512 { /** An interface for configuring and controlling the functionality of a thermostat. */ cluster Thermostat = 513 { - revision 6; + revision 7; enum ACCapacityFormatEnum : enum8 { kBTUh = 0; @@ -6692,7 +6703,6 @@ cluster Thermostat = 513 { } enum PresetScenarioEnum : enum8 { - kUnspecified = 0; kOccupied = 1; kUnoccupied = 2; kSleep = 3; @@ -6765,7 +6775,6 @@ cluster Thermostat = 513 { kLocalTemperatureNotExposed = 0x40; kMatterScheduleConfiguration = 0x80; kPresets = 0x100; - kSetpoints = 0x200; } bitmap HVACSystemTypeBitmap : bitmap8 { @@ -6775,6 +6784,10 @@ cluster Thermostat = 513 { kHeatingUsesFuel = 0x20; } + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + bitmap PresetTypeFeaturesBitmap : bitmap16 { kAutomatic = 0x1; kSupportsNames = 0x2; @@ -6840,7 +6853,7 @@ cluster Thermostat = 513 { optional char_string<64> name = 2; optional octet_string<16> presetHandle = 3; ScheduleTransitionStruct transitions[] = 4; - optional nullable boolean builtIn = 5; + nullable boolean builtIn = 5; } struct PresetStruct { @@ -6872,23 +6885,23 @@ cluster Thermostat = 513 { readonly attribute nullable temperature localTemperature = 0; readonly attribute optional nullable temperature outdoorTemperature = 1; - readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional OccupancyBitmap occupancy = 2; readonly attribute optional temperature absMinHeatSetpointLimit = 3; readonly attribute optional temperature absMaxHeatSetpointLimit = 4; readonly attribute optional temperature absMinCoolSetpointLimit = 5; readonly attribute optional temperature absMaxCoolSetpointLimit = 6; readonly attribute optional int8u PICoolingDemand = 7; readonly attribute optional int8u PIHeatingDemand = 8; - attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; attribute access(write: manage) optional int8s localTemperatureCalibration = 16; - attribute optional int16s occupiedCoolingSetpoint = 17; - attribute optional int16s occupiedHeatingSetpoint = 18; - attribute optional int16s unoccupiedCoolingSetpoint = 19; - attribute optional int16s unoccupiedHeatingSetpoint = 20; - attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; - attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; - attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; - attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; attribute access(write: manage) optional int8s minSetpointDeadBand = 25; attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; @@ -6929,8 +6942,7 @@ cluster Thermostat = 513 { readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; attribute access(write: manage) optional PresetStruct presets[] = 80; attribute access(write: manage) optional ScheduleStruct schedules[] = 81; - readonly attribute optional boolean presetsSchedulesEditable = 82; - readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -6970,28 +6982,32 @@ cluster Thermostat = 513 { octet_string<16> presetHandle = 0; } - request struct StartPresetsSchedulesEditRequestRequest { - int16u timeoutSeconds = 0; + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; } - /** Command description for SetpointRaiseLower */ + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; - /** Command description for SetWeeklySchedule */ + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; - /** Command description for GetWeeklySchedule */ + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; - /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + /** This command is used to clear the weekly schedule. */ command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; - /** This command is used to set the active schedule. */ + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; - /** This command is used to set the active preset. */ + /** ID */ command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; - /** This command is used to start editing the presets and schedules. */ - command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; - /** This command is used to cancel editing presets and schedules. */ - command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; - /** This command is used to notify the server that all edits are done and should be committed. */ - command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; } /** An interface for controlling a fan in a heating/cooling system. */ diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index 2ae10832fd10da..c6a65ba56a6ae6 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -40488,8 +40488,7 @@ public static class ThermostatCluster extends BaseChipCluster { private static final long ACTIVE_SCHEDULE_HANDLE_ATTRIBUTE_ID = 79L; private static final long PRESETS_ATTRIBUTE_ID = 80L; private static final long SCHEDULES_ATTRIBUTE_ID = 81L; - private static final long PRESETS_SCHEDULES_EDITABLE_ATTRIBUTE_ID = 82L; - private static final long SETPOINT_HOLD_EXPIRY_TIMESTAMP_ATTRIBUTE_ID = 83L; + private static final long SETPOINT_HOLD_EXPIRY_TIMESTAMP_ATTRIBUTE_ID = 82L; private static final long GENERATED_COMMAND_LIST_ATTRIBUTE_ID = 65528L; private static final long ACCEPTED_COMMAND_LIST_ATTRIBUTE_ID = 65529L; private static final long EVENT_LIST_ATTRIBUTE_ID = 65530L; @@ -40674,55 +40673,55 @@ public void onResponse(StructType invokeStructValue) { }}, commandId, commandArgs, timedInvokeTimeoutMs); } - public void startPresetsSchedulesEditRequest(DefaultClusterCallback callback, Integer timeoutSeconds) { - startPresetsSchedulesEditRequest(callback, timeoutSeconds, 0); + public void atomicRequest(AtomicResponseCallback callback, Integer requestType, ArrayList attributeRequests, Optional timeout) { + atomicRequest(callback, requestType, attributeRequests, timeout, 0); } - public void startPresetsSchedulesEditRequest(DefaultClusterCallback callback, Integer timeoutSeconds, int timedInvokeTimeoutMs) { - final long commandId = 7L; + public void atomicRequest(AtomicResponseCallback callback, Integer requestType, ArrayList attributeRequests, Optional timeout, int timedInvokeTimeoutMs) { + final long commandId = 254L; ArrayList elements = new ArrayList<>(); - final long timeoutSecondsFieldID = 0L; - BaseTLVType timeoutSecondstlvValue = new UIntType(timeoutSeconds); - elements.add(new StructElement(timeoutSecondsFieldID, timeoutSecondstlvValue)); + final long requestTypeFieldID = 0L; + BaseTLVType requestTypetlvValue = new UIntType(requestType); + elements.add(new StructElement(requestTypeFieldID, requestTypetlvValue)); - StructType commandArgs = new StructType(elements); - invoke(new InvokeCallbackImpl(callback) { - @Override - public void onResponse(StructType invokeStructValue) { - callback.onSuccess(); - }}, commandId, commandArgs, timedInvokeTimeoutMs); - } + final long attributeRequestsFieldID = 1L; + BaseTLVType attributeRequeststlvValue = ArrayType.generateArrayType(attributeRequests, (elementattributeRequests) -> new UIntType(elementattributeRequests)); + elements.add(new StructElement(attributeRequestsFieldID, attributeRequeststlvValue)); - public void cancelPresetsSchedulesEditRequest(DefaultClusterCallback callback) { - cancelPresetsSchedulesEditRequest(callback, 0); - } - - public void cancelPresetsSchedulesEditRequest(DefaultClusterCallback callback, int timedInvokeTimeoutMs) { - final long commandId = 8L; - - ArrayList elements = new ArrayList<>(); - StructType commandArgs = new StructType(elements); - invoke(new InvokeCallbackImpl(callback) { - @Override - public void onResponse(StructType invokeStructValue) { - callback.onSuccess(); - }}, commandId, commandArgs, timedInvokeTimeoutMs); - } - - public void commitPresetsSchedulesRequest(DefaultClusterCallback callback) { - commitPresetsSchedulesRequest(callback, 0); - } - - public void commitPresetsSchedulesRequest(DefaultClusterCallback callback, int timedInvokeTimeoutMs) { - final long commandId = 9L; + final long timeoutFieldID = 2L; + BaseTLVType timeouttlvValue = timeout.map((nonOptionaltimeout) -> new UIntType(nonOptionaltimeout)).orElse(new EmptyType()); + elements.add(new StructElement(timeoutFieldID, timeouttlvValue)); - ArrayList elements = new ArrayList<>(); StructType commandArgs = new StructType(elements); invoke(new InvokeCallbackImpl(callback) { @Override public void onResponse(StructType invokeStructValue) { - callback.onSuccess(); + final long statusCodeFieldID = 0L; + Integer statusCode = null; + final long attributeStatusFieldID = 1L; + ArrayList attributeStatus = null; + final long timeoutFieldID = 2L; + Optional timeout = Optional.empty(); + for (StructElement element: invokeStructValue.value()) { + if (element.contextTagNum() == statusCodeFieldID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + statusCode = castingValue.value(Integer.class); + } + } else if (element.contextTagNum() == attributeStatusFieldID) { + if (element.value(BaseTLVType.class).type() == TLVType.Array) { + ArrayType castingValue = element.value(ArrayType.class); + attributeStatus = castingValue.map((elementcastingValue) -> ChipStructs.ThermostatClusterAtomicAttributeStatusStruct.decodeTlv(elementcastingValue)); + } + } else if (element.contextTagNum() == timeoutFieldID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + timeout = Optional.of(castingValue.value(Integer.class)); + } + } + } + callback.onSuccess(statusCode, attributeStatus, timeout); }}, commandId, commandArgs, timedInvokeTimeoutMs); } @@ -40730,6 +40729,10 @@ public interface GetWeeklyScheduleResponseCallback extends BaseClusterCallback { void onSuccess(Integer numberOfTransitionsForSequence, Integer dayOfWeekForSequence, Integer modeForSequence, ArrayList transitions); } + public interface AtomicResponseCallback extends BaseClusterCallback { + void onSuccess(Integer statusCode, ArrayList attributeStatus, Optional timeout); + } + public interface LocalTemperatureAttributeCallback extends BaseAttributeCallback { void onSuccess(@Nullable Integer value); } @@ -42617,32 +42620,6 @@ public void onSuccess(byte[] tlv) { }, SCHEDULES_ATTRIBUTE_ID, minInterval, maxInterval); } - public void readPresetsSchedulesEditableAttribute( - BooleanAttributeCallback callback) { - ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, PRESETS_SCHEDULES_EDITABLE_ATTRIBUTE_ID); - - readAttribute(new ReportCallbackImpl(callback, path) { - @Override - public void onSuccess(byte[] tlv) { - Boolean value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); - callback.onSuccess(value); - } - }, PRESETS_SCHEDULES_EDITABLE_ATTRIBUTE_ID, true); - } - - public void subscribePresetsSchedulesEditableAttribute( - BooleanAttributeCallback callback, int minInterval, int maxInterval) { - ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, PRESETS_SCHEDULES_EDITABLE_ATTRIBUTE_ID); - - subscribeAttribute(new ReportCallbackImpl(callback, path) { - @Override - public void onSuccess(byte[] tlv) { - Boolean value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); - callback.onSuccess(value); - } - }, PRESETS_SCHEDULES_EDITABLE_ATTRIBUTE_ID, minInterval, maxInterval); - } - public void readSetpointHoldExpiryTimestampAttribute( SetpointHoldExpiryTimestampAttributeCallback callback) { ChipAttributePath path = ChipAttributePath.newInstance(endpointId, clusterId, SETPOINT_HOLD_EXPIRY_TIMESTAMP_ATTRIBUTE_ID); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java b/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java index 330ee797fb6ecb..9a410a6a8c8d59 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipStructs.java @@ -9693,7 +9693,7 @@ public static class ThermostatClusterScheduleStruct { public Optional name; public Optional presetHandle; public ArrayList transitions; - public @Nullable Optional builtIn; + public @Nullable Boolean builtIn; private static final long SCHEDULE_HANDLE_ID = 0L; private static final long SYSTEM_MODE_ID = 1L; private static final long NAME_ID = 2L; @@ -9707,7 +9707,7 @@ public ThermostatClusterScheduleStruct( Optional name, Optional presetHandle, ArrayList transitions, - @Nullable Optional builtIn + @Nullable Boolean builtIn ) { this.scheduleHandle = scheduleHandle; this.systemMode = systemMode; @@ -9724,7 +9724,7 @@ public StructType encodeTlv() { values.add(new StructElement(NAME_ID, name.map((nonOptionalname) -> new StringType(nonOptionalname)).orElse(new EmptyType()))); values.add(new StructElement(PRESET_HANDLE_ID, presetHandle.map((nonOptionalpresetHandle) -> new ByteArrayType(nonOptionalpresetHandle)).orElse(new EmptyType()))); values.add(new StructElement(TRANSITIONS_ID, ArrayType.generateArrayType(transitions, (elementtransitions) -> elementtransitions.encodeTlv()))); - values.add(new StructElement(BUILT_IN_ID, builtIn != null ? builtIn.map((nonOptionalbuiltIn) -> new BooleanType(nonOptionalbuiltIn)).orElse(new EmptyType()) : new NullType())); + values.add(new StructElement(BUILT_IN_ID, builtIn != null ? new BooleanType(builtIn) : new NullType())); return new StructType(values); } @@ -9738,7 +9738,7 @@ public static ThermostatClusterScheduleStruct decodeTlv(BaseTLVType tlvValue) { Optional name = Optional.empty(); Optional presetHandle = Optional.empty(); ArrayList transitions = null; - @Nullable Optional builtIn = null; + @Nullable Boolean builtIn = null; for (StructElement element: ((StructType)tlvValue).value()) { if (element.contextTagNum() == SCHEDULE_HANDLE_ID) { if (element.value(BaseTLVType.class).type() == TLVType.ByteArray) { @@ -9768,7 +9768,7 @@ public static ThermostatClusterScheduleStruct decodeTlv(BaseTLVType tlvValue) { } else if (element.contextTagNum() == BUILT_IN_ID) { if (element.value(BaseTLVType.class).type() == TLVType.Boolean) { BooleanType castingValue = element.value(BooleanType.class); - builtIn = Optional.of(castingValue.value(Boolean.class)); + builtIn = castingValue.value(Boolean.class); } } } @@ -10157,6 +10157,67 @@ public String toString() { return output.toString(); } } +public static class ThermostatClusterAtomicAttributeStatusStruct { + public Long attributeID; + public Integer statusCode; + private static final long ATTRIBUTE_I_D_ID = 0L; + private static final long STATUS_CODE_ID = 1L; + + public ThermostatClusterAtomicAttributeStatusStruct( + Long attributeID, + Integer statusCode + ) { + this.attributeID = attributeID; + this.statusCode = statusCode; + } + + public StructType encodeTlv() { + ArrayList values = new ArrayList<>(); + values.add(new StructElement(ATTRIBUTE_I_D_ID, new UIntType(attributeID))); + values.add(new StructElement(STATUS_CODE_ID, new UIntType(statusCode))); + + return new StructType(values); + } + + public static ThermostatClusterAtomicAttributeStatusStruct decodeTlv(BaseTLVType tlvValue) { + if (tlvValue == null || tlvValue.type() != TLVType.Struct) { + return null; + } + Long attributeID = null; + Integer statusCode = null; + for (StructElement element: ((StructType)tlvValue).value()) { + if (element.contextTagNum() == ATTRIBUTE_I_D_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + attributeID = castingValue.value(Long.class); + } + } else if (element.contextTagNum() == STATUS_CODE_ID) { + if (element.value(BaseTLVType.class).type() == TLVType.UInt) { + UIntType castingValue = element.value(UIntType.class); + statusCode = castingValue.value(Integer.class); + } + } + } + return new ThermostatClusterAtomicAttributeStatusStruct( + attributeID, + statusCode + ); + } + + @Override + public String toString() { + StringBuilder output = new StringBuilder(); + output.append("ThermostatClusterAtomicAttributeStatusStruct {\n"); + output.append("\tattributeID: "); + output.append(attributeID); + output.append("\n"); + output.append("\tstatusCode: "); + output.append(statusCode); + output.append("\n"); + output.append("}\n"); + return output.toString(); + } +} public static class OccupancySensingClusterHoldTimeLimitsStruct { public Integer holdTimeMin; public Integer holdTimeMax; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java index 0f5e910682a659..9a5fd5658ea2dd 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterIDMapping.java @@ -11958,8 +11958,7 @@ public enum Attribute { ActiveScheduleHandle(79L), Presets(80L), Schedules(81L), - PresetsSchedulesEditable(82L), - SetpointHoldExpiryTimestamp(83L), + SetpointHoldExpiryTimestamp(82L), GeneratedCommandList(65528L), AcceptedCommandList(65529L), EventList(65530L), @@ -12012,9 +12011,7 @@ public enum Command { ClearWeeklySchedule(3L), SetActiveScheduleRequest(5L), SetActivePresetRequest(6L), - StartPresetsSchedulesEditRequest(7L), - CancelPresetsSchedulesEditRequest(8L), - CommitPresetsSchedulesRequest(9L),; + AtomicRequest(254L),; private final long id; Command(long id) { this.id = id; @@ -12117,17 +12114,17 @@ public static SetActivePresetRequestCommandField value(int id) throws NoSuchFiel } throw new NoSuchFieldError(); } - }public enum StartPresetsSchedulesEditRequestCommandField {TimeoutSeconds(0),; + }public enum AtomicRequestCommandField {RequestType(0),AttributeRequests(1),Timeout(2),; private final int id; - StartPresetsSchedulesEditRequestCommandField(int id) { + AtomicRequestCommandField(int id) { this.id = id; } public int getID() { return id; } - public static StartPresetsSchedulesEditRequestCommandField value(int id) throws NoSuchFieldError { - for (StartPresetsSchedulesEditRequestCommandField field : StartPresetsSchedulesEditRequestCommandField.values()) { + public static AtomicRequestCommandField value(int id) throws NoSuchFieldError { + for (AtomicRequestCommandField field : AtomicRequestCommandField.values()) { if (field.getID() == id) { return field; } diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java index 44faa837ffff66..7b3f36e2f0fb83 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java @@ -13865,6 +13865,33 @@ public void onError(Exception error) { callback.onFailure(error); } } + + public static class DelegatedThermostatClusterAtomicResponseCallback implements ChipClusters.ThermostatCluster.AtomicResponseCallback, DelegatedClusterCallback { + private ClusterCommandCallback callback; + @Override + public void setCallbackDelegate(ClusterCommandCallback callback) { + this.callback = callback; + } + + @Override + public void onSuccess(Integer statusCode, ArrayList attributeStatus, Optional timeout) { + Map responseValues = new LinkedHashMap<>(); + + CommandResponseInfo statusCodeResponseValue = new CommandResponseInfo("statusCode", "Integer"); + responseValues.put(statusCodeResponseValue, statusCode); + // attributeStatus: AtomicAttributeStatusStruct + // Conversion from this type to Java is not properly implemented yet + + CommandResponseInfo timeoutResponseValue = new CommandResponseInfo("timeout", "Optional"); + responseValues.put(timeoutResponseValue, timeout); + callback.onSuccess(responseValues); + } + + @Override + public void onError(Exception error) { + callback.onFailure(error); + } + } public static class DelegatedThermostatClusterLocalTemperatureAttributeCallback implements ChipClusters.ThermostatCluster.LocalTemperatureAttributeCallback, DelegatedClusterCallback { private ClusterCommandCallback callback; @Override @@ -27078,46 +27105,35 @@ public Map> getCommandMap() { ); thermostatClusterInteractionInfoMap.put("setActivePresetRequest", thermostatsetActivePresetRequestInteractionInfo); - Map thermostatstartPresetsSchedulesEditRequestCommandParams = new LinkedHashMap(); + Map thermostatatomicRequestCommandParams = new LinkedHashMap(); - CommandParameterInfo thermostatstartPresetsSchedulesEditRequesttimeoutSecondsCommandParameterInfo = new CommandParameterInfo("timeoutSeconds", Integer.class, Integer.class); - thermostatstartPresetsSchedulesEditRequestCommandParams.put("timeoutSeconds",thermostatstartPresetsSchedulesEditRequesttimeoutSecondsCommandParameterInfo); - InteractionInfo thermostatstartPresetsSchedulesEditRequestInteractionInfo = new InteractionInfo( - (cluster, callback, commandArguments) -> { - ((ChipClusters.ThermostatCluster) cluster) - .startPresetsSchedulesEditRequest((DefaultClusterCallback) callback - , (Integer) - commandArguments.get("timeoutSeconds") - ); - }, - () -> new DelegatedDefaultClusterCallback(), - thermostatstartPresetsSchedulesEditRequestCommandParams - ); - thermostatClusterInteractionInfoMap.put("startPresetsSchedulesEditRequest", thermostatstartPresetsSchedulesEditRequestInteractionInfo); + CommandParameterInfo thermostatatomicRequestrequestTypeCommandParameterInfo = new CommandParameterInfo("requestType", Integer.class, Integer.class); + thermostatatomicRequestCommandParams.put("requestType",thermostatatomicRequestrequestTypeCommandParameterInfo); - Map thermostatcancelPresetsSchedulesEditRequestCommandParams = new LinkedHashMap(); - InteractionInfo thermostatcancelPresetsSchedulesEditRequestInteractionInfo = new InteractionInfo( - (cluster, callback, commandArguments) -> { - ((ChipClusters.ThermostatCluster) cluster) - .cancelPresetsSchedulesEditRequest((DefaultClusterCallback) callback - ); - }, - () -> new DelegatedDefaultClusterCallback(), - thermostatcancelPresetsSchedulesEditRequestCommandParams - ); - thermostatClusterInteractionInfoMap.put("cancelPresetsSchedulesEditRequest", thermostatcancelPresetsSchedulesEditRequestInteractionInfo); + CommandParameterInfo thermostatatomicRequestattributeRequestsCommandParameterInfo = new CommandParameterInfo("attributeRequests", ArrayList.class, ArrayList.class); + thermostatatomicRequestCommandParams.put("attributeRequests",thermostatatomicRequestattributeRequestsCommandParameterInfo); - Map thermostatcommitPresetsSchedulesRequestCommandParams = new LinkedHashMap(); - InteractionInfo thermostatcommitPresetsSchedulesRequestInteractionInfo = new InteractionInfo( + CommandParameterInfo thermostatatomicRequesttimeoutCommandParameterInfo = new CommandParameterInfo("timeout", Optional.class, Integer.class); + thermostatatomicRequestCommandParams.put("timeout",thermostatatomicRequesttimeoutCommandParameterInfo); + InteractionInfo thermostatatomicRequestInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { ((ChipClusters.ThermostatCluster) cluster) - .commitPresetsSchedulesRequest((DefaultClusterCallback) callback - ); - }, - () -> new DelegatedDefaultClusterCallback(), - thermostatcommitPresetsSchedulesRequestCommandParams - ); - thermostatClusterInteractionInfoMap.put("commitPresetsSchedulesRequest", thermostatcommitPresetsSchedulesRequestInteractionInfo); + .atomicRequest((ChipClusters.ThermostatCluster.AtomicResponseCallback) callback + , (Integer) + commandArguments.get("requestType") + + , (ArrayList) + commandArguments.get("attributeRequests") + + , (Optional) + commandArguments.get("timeout") + + ); + }, + () -> new DelegatedThermostatClusterAtomicResponseCallback(), + thermostatatomicRequestCommandParams + ); + thermostatClusterInteractionInfoMap.put("atomicRequest", thermostatatomicRequestInteractionInfo); commandMap.put("thermostat", thermostatClusterInteractionInfoMap); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java index 64c2ae23902025..7aa5a710554223 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterReadMapping.java @@ -12971,17 +12971,6 @@ private static Map readThermostatInteractionInfo() { readThermostatSchedulesCommandParams ); result.put("readSchedulesAttribute", readThermostatSchedulesAttributeInteractionInfo); - Map readThermostatPresetsSchedulesEditableCommandParams = new LinkedHashMap(); - InteractionInfo readThermostatPresetsSchedulesEditableAttributeInteractionInfo = new InteractionInfo( - (cluster, callback, commandArguments) -> { - ((ChipClusters.ThermostatCluster) cluster).readPresetsSchedulesEditableAttribute( - (ChipClusters.BooleanAttributeCallback) callback - ); - }, - () -> new ClusterInfoMapping.DelegatedBooleanAttributeCallback(), - readThermostatPresetsSchedulesEditableCommandParams - ); - result.put("readPresetsSchedulesEditableAttribute", readThermostatPresetsSchedulesEditableAttributeInteractionInfo); Map readThermostatSetpointHoldExpiryTimestampCommandParams = new LinkedHashMap(); InteractionInfo readThermostatSetpointHoldExpiryTimestampAttributeInteractionInfo = new InteractionInfo( (cluster, callback, commandArguments) -> { diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni index df66c2aa0e51aa..1b0bd261bb6c31 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/files.gni @@ -130,6 +130,7 @@ structs_sources = [ "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ServiceAreaClusterProgressStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/SoftwareDiagnosticsClusterThreadMetricsStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/TargetNavigatorClusterTargetInfoStruct.kt", + "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThermostatClusterAtomicAttributeStatusStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThermostatClusterPresetStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThermostatClusterPresetTypeStruct.kt", "${chip_root}/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThermostatClusterScheduleStruct.kt", diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThermostatClusterAtomicAttributeStatusStruct.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThermostatClusterAtomicAttributeStatusStruct.kt new file mode 100644 index 00000000000000..7500a9619d6973 --- /dev/null +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThermostatClusterAtomicAttributeStatusStruct.kt @@ -0,0 +1,56 @@ +/* + * + * 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. + */ +package chip.devicecontroller.cluster.structs + +import chip.devicecontroller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class ThermostatClusterAtomicAttributeStatusStruct(val attributeID: ULong, val statusCode: UInt) { + override fun toString(): String = buildString { + append("ThermostatClusterAtomicAttributeStatusStruct {\n") + append("\tattributeID : $attributeID\n") + append("\tstatusCode : $statusCode\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_ATTRIBUTE_I_D), attributeID) + put(ContextSpecificTag(TAG_STATUS_CODE), statusCode) + endStructure() + } + } + + companion object { + private const val TAG_ATTRIBUTE_I_D = 0 + private const val TAG_STATUS_CODE = 1 + + fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): ThermostatClusterAtomicAttributeStatusStruct { + tlvReader.enterStructure(tlvTag) + val attributeID = tlvReader.getULong(ContextSpecificTag(TAG_ATTRIBUTE_I_D)) + val statusCode = tlvReader.getUInt(ContextSpecificTag(TAG_STATUS_CODE)) + + tlvReader.exitContainer() + + return ThermostatClusterAtomicAttributeStatusStruct(attributeID, statusCode) + } + } +} diff --git a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThermostatClusterScheduleStruct.kt b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThermostatClusterScheduleStruct.kt index 6a3b8727c32860..e05123dd91f361 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThermostatClusterScheduleStruct.kt +++ b/src/controller/java/generated/java/chip/devicecontroller/cluster/structs/ThermostatClusterScheduleStruct.kt @@ -30,7 +30,7 @@ class ThermostatClusterScheduleStruct( val name: Optional, val presetHandle: Optional, val transitions: List, - val builtIn: Optional?, + val builtIn: Boolean?, ) { override fun toString(): String = buildString { append("ThermostatClusterScheduleStruct {\n") @@ -66,10 +66,7 @@ class ThermostatClusterScheduleStruct( } endArray() if (builtIn != null) { - if (builtIn.isPresent) { - val optbuiltIn = builtIn.get() - put(ContextSpecificTag(TAG_BUILT_IN), optbuiltIn) - } + put(ContextSpecificTag(TAG_BUILT_IN), builtIn) } else { putNull(ContextSpecificTag(TAG_BUILT_IN)) } @@ -117,11 +114,7 @@ class ThermostatClusterScheduleStruct( } val builtIn = if (!tlvReader.isNull()) { - if (tlvReader.isNextTag(ContextSpecificTag(TAG_BUILT_IN))) { - Optional.of(tlvReader.getBoolean(ContextSpecificTag(TAG_BUILT_IN))) - } else { - Optional.empty() - } + tlvReader.getBoolean(ContextSpecificTag(TAG_BUILT_IN)) } else { tlvReader.getNull(ContextSpecificTag(TAG_BUILT_IN)) null diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ThermostatCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ThermostatCluster.kt index 66db507eb79cd5..b9166c12e937a1 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ThermostatCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ThermostatCluster.kt @@ -22,7 +22,6 @@ import java.util.logging.Level import java.util.logging.Logger import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.transform -import matter.controller.BooleanSubscriptionState import matter.controller.ByteSubscriptionState import matter.controller.InvokeRequest import matter.controller.InvokeResponse @@ -54,6 +53,12 @@ class ThermostatCluster(private val controller: MatterController, private val en val transitions: List, ) + class AtomicResponse( + val statusCode: UByte, + val attributeStatus: List, + val timeout: UShort?, + ) + class LocalTemperatureAttribute(val value: Short?) sealed class LocalTemperatureAttributeSubscriptionState { @@ -522,17 +527,29 @@ class ThermostatCluster(private val controller: MatterController, private val en logger.log(Level.FINE, "Invoke command succeeded: ${response}") } - suspend fun startPresetsSchedulesEditRequest( - timeoutSeconds: UShort, + suspend fun atomicRequest( + requestType: UByte, + attributeRequests: List, + timeout: UShort?, timedInvokeTimeout: Duration? = null, - ) { - val commandId: UInt = 7u + ): AtomicResponse { + val commandId: UInt = 254u val tlvWriter = TlvWriter() tlvWriter.startStructure(AnonymousTag) - val TAG_TIMEOUT_SECONDS_REQ: Int = 0 - tlvWriter.put(ContextSpecificTag(TAG_TIMEOUT_SECONDS_REQ), timeoutSeconds) + val TAG_REQUEST_TYPE_REQ: Int = 0 + tlvWriter.put(ContextSpecificTag(TAG_REQUEST_TYPE_REQ), requestType) + + val TAG_ATTRIBUTE_REQUESTS_REQ: Int = 1 + tlvWriter.startArray(ContextSpecificTag(TAG_ATTRIBUTE_REQUESTS_REQ)) + for (item in attributeRequests.iterator()) { + tlvWriter.put(AnonymousTag, item) + } + tlvWriter.endArray() + + val TAG_TIMEOUT_REQ: Int = 2 + timeout?.let { tlvWriter.put(ContextSpecificTag(TAG_TIMEOUT_REQ), timeout) } tlvWriter.endStructure() val request: InvokeRequest = @@ -544,42 +561,64 @@ class ThermostatCluster(private val controller: MatterController, private val en val response: InvokeResponse = controller.invoke(request) logger.log(Level.FINE, "Invoke command succeeded: ${response}") - } - suspend fun cancelPresetsSchedulesEditRequest(timedInvokeTimeout: Duration? = null) { - val commandId: UInt = 8u + val tlvReader = TlvReader(response.payload) + tlvReader.enterStructure(AnonymousTag) + val TAG_STATUS_CODE: Int = 0 + var statusCode_decoded: UByte? = null - val tlvWriter = TlvWriter() - tlvWriter.startStructure(AnonymousTag) - tlvWriter.endStructure() + val TAG_ATTRIBUTE_STATUS: Int = 1 + var attributeStatus_decoded: List? = null - val request: InvokeRequest = - InvokeRequest( - CommandPath(endpointId, clusterId = CLUSTER_ID, commandId), - tlvPayload = tlvWriter.getEncoded(), - timedRequest = timedInvokeTimeout, - ) + val TAG_TIMEOUT: Int = 2 + var timeout_decoded: UShort? = null - val response: InvokeResponse = controller.invoke(request) - logger.log(Level.FINE, "Invoke command succeeded: ${response}") - } + while (!tlvReader.isEndOfContainer()) { + val tag = tlvReader.peekElement().tag - suspend fun commitPresetsSchedulesRequest(timedInvokeTimeout: Duration? = null) { - val commandId: UInt = 9u + if (tag == ContextSpecificTag(TAG_STATUS_CODE)) { + statusCode_decoded = tlvReader.getUByte(tag) + } - val tlvWriter = TlvWriter() - tlvWriter.startStructure(AnonymousTag) - tlvWriter.endStructure() + if (tag == ContextSpecificTag(TAG_ATTRIBUTE_STATUS)) { + attributeStatus_decoded = + buildList { + tlvReader.enterArray(tag) + while (!tlvReader.isEndOfContainer()) { + add(ThermostatClusterAtomicAttributeStatusStruct.fromTlv(AnonymousTag, tlvReader)) + } + tlvReader.exitContainer() + } + } - val request: InvokeRequest = - InvokeRequest( - CommandPath(endpointId, clusterId = CLUSTER_ID, commandId), - tlvPayload = tlvWriter.getEncoded(), - timedRequest = timedInvokeTimeout, - ) + if (tag == ContextSpecificTag(TAG_TIMEOUT)) { + timeout_decoded = + if (tlvReader.isNull()) { + tlvReader.getNull(tag) + null + } else { + if (tlvReader.isNextTag(tag)) { + tlvReader.getUShort(tag) + } else { + null + } + } + } else { + tlvReader.skipElement() + } + } - val response: InvokeResponse = controller.invoke(request) - logger.log(Level.FINE, "Invoke command succeeded: ${response}") + if (statusCode_decoded == null) { + throw IllegalStateException("statusCode not found in TLV") + } + + if (attributeStatus_decoded == null) { + throw IllegalStateException("attributeStatus not found in TLV") + } + + tlvReader.exitContainer() + + return AtomicResponse(statusCode_decoded, attributeStatus_decoded, timeout_decoded) } suspend fun readLocalTemperatureAttribute(): LocalTemperatureAttribute { @@ -7437,101 +7476,8 @@ class ThermostatCluster(private val controller: MatterController, private val en } } - suspend fun readPresetsSchedulesEditableAttribute(): Boolean? { - val ATTRIBUTE_ID: UInt = 82u - - val attributePath = - AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) - - val readRequest = ReadRequest(eventPaths = emptyList(), attributePaths = listOf(attributePath)) - - val response = controller.read(readRequest) - - if (response.successes.isEmpty()) { - logger.log(Level.WARNING, "Read command failed") - throw IllegalStateException("Read command failed with failures: ${response.failures}") - } - - logger.log(Level.FINE, "Read command succeeded") - - val attributeData = - response.successes.filterIsInstance().firstOrNull { - it.path.attributeId == ATTRIBUTE_ID - } - - requireNotNull(attributeData) { "Presetsscheduleseditable attribute not found in response" } - - // Decode the TLV data into the appropriate type - val tlvReader = TlvReader(attributeData.data) - val decodedValue: Boolean? = - if (tlvReader.isNextTag(AnonymousTag)) { - tlvReader.getBoolean(AnonymousTag) - } else { - null - } - - return decodedValue - } - - suspend fun subscribePresetsSchedulesEditableAttribute( - minInterval: Int, - maxInterval: Int, - ): Flow { - val ATTRIBUTE_ID: UInt = 82u - val attributePaths = - listOf( - AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) - ) - - val subscribeRequest: SubscribeRequest = - SubscribeRequest( - eventPaths = emptyList(), - attributePaths = attributePaths, - minInterval = Duration.ofSeconds(minInterval.toLong()), - maxInterval = Duration.ofSeconds(maxInterval.toLong()), - ) - - return controller.subscribe(subscribeRequest).transform { subscriptionState -> - when (subscriptionState) { - is SubscriptionState.SubscriptionErrorNotification -> { - emit( - BooleanSubscriptionState.Error( - Exception( - "Subscription terminated with error code: ${subscriptionState.terminationCause}" - ) - ) - ) - } - is SubscriptionState.NodeStateUpdate -> { - val attributeData = - subscriptionState.updateState.successes - .filterIsInstance() - .firstOrNull { it.path.attributeId == ATTRIBUTE_ID } - - requireNotNull(attributeData) { - "Presetsscheduleseditable attribute not found in Node State update" - } - - // Decode the TLV data into the appropriate type - val tlvReader = TlvReader(attributeData.data) - val decodedValue: Boolean? = - if (tlvReader.isNextTag(AnonymousTag)) { - tlvReader.getBoolean(AnonymousTag) - } else { - null - } - - decodedValue?.let { emit(BooleanSubscriptionState.Success(it)) } - } - SubscriptionState.SubscriptionEstablished -> { - emit(BooleanSubscriptionState.SubscriptionEstablished) - } - } - } - } - suspend fun readSetpointHoldExpiryTimestampAttribute(): SetpointHoldExpiryTimestampAttribute { - val ATTRIBUTE_ID: UInt = 83u + val ATTRIBUTE_ID: UInt = 82u val attributePath = AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) @@ -7575,7 +7521,7 @@ class ThermostatCluster(private val controller: MatterController, private val en minInterval: Int, maxInterval: Int, ): Flow { - val ATTRIBUTE_ID: UInt = 83u + val ATTRIBUTE_ID: UInt = 82u val attributePaths = listOf( AttributePath(endpointId = endpointId, clusterId = CLUSTER_ID, attributeId = ATTRIBUTE_ID) diff --git a/src/controller/java/generated/java/matter/controller/cluster/files.gni b/src/controller/java/generated/java/matter/controller/cluster/files.gni index 31d51e53f76758..e848af60d78a98 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/files.gni +++ b/src/controller/java/generated/java/matter/controller/cluster/files.gni @@ -130,6 +130,7 @@ matter_structs_sources = [ "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ServiceAreaClusterProgressStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/SoftwareDiagnosticsClusterThreadMetricsStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/TargetNavigatorClusterTargetInfoStruct.kt", + "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ThermostatClusterAtomicAttributeStatusStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ThermostatClusterPresetStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ThermostatClusterPresetTypeStruct.kt", "${chip_root}/src/controller/java/generated/java/matter/controller/cluster/structs/ThermostatClusterScheduleStruct.kt", diff --git a/src/controller/java/generated/java/matter/controller/cluster/structs/ThermostatClusterAtomicAttributeStatusStruct.kt b/src/controller/java/generated/java/matter/controller/cluster/structs/ThermostatClusterAtomicAttributeStatusStruct.kt new file mode 100644 index 00000000000000..2a67c0cccb8688 --- /dev/null +++ b/src/controller/java/generated/java/matter/controller/cluster/structs/ThermostatClusterAtomicAttributeStatusStruct.kt @@ -0,0 +1,56 @@ +/* + * + * 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. + */ +package matter.controller.cluster.structs + +import matter.controller.cluster.* +import matter.tlv.ContextSpecificTag +import matter.tlv.Tag +import matter.tlv.TlvReader +import matter.tlv.TlvWriter + +class ThermostatClusterAtomicAttributeStatusStruct(val attributeID: UInt, val statusCode: UByte) { + override fun toString(): String = buildString { + append("ThermostatClusterAtomicAttributeStatusStruct {\n") + append("\tattributeID : $attributeID\n") + append("\tstatusCode : $statusCode\n") + append("}\n") + } + + fun toTlv(tlvTag: Tag, tlvWriter: TlvWriter) { + tlvWriter.apply { + startStructure(tlvTag) + put(ContextSpecificTag(TAG_ATTRIBUTE_I_D), attributeID) + put(ContextSpecificTag(TAG_STATUS_CODE), statusCode) + endStructure() + } + } + + companion object { + private const val TAG_ATTRIBUTE_I_D = 0 + private const val TAG_STATUS_CODE = 1 + + fun fromTlv(tlvTag: Tag, tlvReader: TlvReader): ThermostatClusterAtomicAttributeStatusStruct { + tlvReader.enterStructure(tlvTag) + val attributeID = tlvReader.getUInt(ContextSpecificTag(TAG_ATTRIBUTE_I_D)) + val statusCode = tlvReader.getUByte(ContextSpecificTag(TAG_STATUS_CODE)) + + tlvReader.exitContainer() + + return ThermostatClusterAtomicAttributeStatusStruct(attributeID, statusCode) + } + } +} diff --git a/src/controller/java/generated/java/matter/controller/cluster/structs/ThermostatClusterScheduleStruct.kt b/src/controller/java/generated/java/matter/controller/cluster/structs/ThermostatClusterScheduleStruct.kt index 720dfaf37afadd..90ca5ab50b6514 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/structs/ThermostatClusterScheduleStruct.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/structs/ThermostatClusterScheduleStruct.kt @@ -30,7 +30,7 @@ class ThermostatClusterScheduleStruct( val name: Optional, val presetHandle: Optional, val transitions: List, - val builtIn: Optional?, + val builtIn: Boolean?, ) { override fun toString(): String = buildString { append("ThermostatClusterScheduleStruct {\n") @@ -66,10 +66,7 @@ class ThermostatClusterScheduleStruct( } endArray() if (builtIn != null) { - if (builtIn.isPresent) { - val optbuiltIn = builtIn.get() - put(ContextSpecificTag(TAG_BUILT_IN), optbuiltIn) - } + put(ContextSpecificTag(TAG_BUILT_IN), builtIn) } else { putNull(ContextSpecificTag(TAG_BUILT_IN)) } @@ -117,11 +114,7 @@ class ThermostatClusterScheduleStruct( } val builtIn = if (!tlvReader.isNull()) { - if (tlvReader.isNextTag(ContextSpecificTag(TAG_BUILT_IN))) { - Optional.of(tlvReader.getBoolean(ContextSpecificTag(TAG_BUILT_IN))) - } else { - Optional.empty() - } + tlvReader.getBoolean(ContextSpecificTag(TAG_BUILT_IN)) } else { tlvReader.getNull(ContextSpecificTag(TAG_BUILT_IN)) null diff --git a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp index 090428ca3fe7eb..81cd1313270c54 100644 --- a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp @@ -29898,7 +29898,7 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR jobject value; std::string valueClassName = "java/lang/Integer"; std::string valueCtorSignature = "(I)V"; - jint jnivalue = static_cast(cppValue); + jint jnivalue = static_cast(cppValue.Raw()); chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), jnivalue, value); return value; @@ -30010,7 +30010,7 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR jobject value; std::string valueClassName = "java/lang/Integer"; std::string valueCtorSignature = "(I)V"; - jint jnivalue = static_cast(cppValue); + jint jnivalue = static_cast(cppValue.Raw()); chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), jnivalue, value); return value; @@ -31268,28 +31268,18 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR chip::JniReferences::GetInstance().AddToList(newElement_0_transitions, newElement_2); } jobject newElement_0_builtIn; - if (!entry_0.builtIn.HasValue()) + if (entry_0.builtIn.IsNull()) { - chip::JniReferences::GetInstance().CreateOptional(nullptr, newElement_0_builtIn); + newElement_0_builtIn = nullptr; } else { - jobject newElement_0_builtInInsideOptional; - if (entry_0.builtIn.Value().IsNull()) - { - newElement_0_builtInInsideOptional = nullptr; - } - else - { - std::string newElement_0_builtInInsideOptionalClassName = "java/lang/Boolean"; - std::string newElement_0_builtInInsideOptionalCtorSignature = "(Z)V"; - jboolean jninewElement_0_builtInInsideOptional = static_cast(entry_0.builtIn.Value().Value()); - chip::JniReferences::GetInstance().CreateBoxedObject( - newElement_0_builtInInsideOptionalClassName.c_str(), - newElement_0_builtInInsideOptionalCtorSignature.c_str(), jninewElement_0_builtInInsideOptional, - newElement_0_builtInInsideOptional); - } - chip::JniReferences::GetInstance().CreateOptional(newElement_0_builtInInsideOptional, newElement_0_builtIn); + std::string newElement_0_builtInClassName = "java/lang/Boolean"; + std::string newElement_0_builtInCtorSignature = "(Z)V"; + jboolean jninewElement_0_builtIn = static_cast(entry_0.builtIn.Value()); + chip::JniReferences::GetInstance().CreateBoxedObject(newElement_0_builtInClassName.c_str(), + newElement_0_builtInCtorSignature.c_str(), + jninewElement_0_builtIn, newElement_0_builtIn); } jclass scheduleStructStructClass_1; @@ -31304,7 +31294,7 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR jmethodID scheduleStructStructCtor_1; err = chip::JniReferences::GetInstance().FindMethod( env, scheduleStructStructClass_1, "", - "([BLjava/lang/Integer;Ljava/util/Optional;Ljava/util/Optional;Ljava/util/ArrayList;Ljava/util/Optional;)V", + "([BLjava/lang/Integer;Ljava/util/Optional;Ljava/util/Optional;Ljava/util/ArrayList;Ljava/lang/Boolean;)V", &scheduleStructStructCtor_1); if (err != CHIP_NO_ERROR || scheduleStructStructCtor_1 == nullptr) { @@ -31319,22 +31309,6 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR } return value; } - case Attributes::PresetsSchedulesEditable::Id: { - using TypeInfo = Attributes::PresetsSchedulesEditable::TypeInfo; - TypeInfo::DecodableType cppValue; - *aError = app::DataModel::Decode(aReader, cppValue); - if (*aError != CHIP_NO_ERROR) - { - return nullptr; - } - jobject value; - std::string valueClassName = "java/lang/Boolean"; - std::string valueCtorSignature = "(Z)V"; - jboolean jnivalue = static_cast(cppValue); - chip::JniReferences::GetInstance().CreateBoxedObject(valueClassName.c_str(), valueCtorSignature.c_str(), - jnivalue, value); - return value; - } case Attributes::SetpointHoldExpiryTimestamp::Id: { using TypeInfo = Attributes::SetpointHoldExpiryTimestamp::TypeInfo; TypeInfo::DecodableType cppValue; diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index c8fe72913b6b67..e8972863a72dca 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -8885,23 +8885,13 @@ class ChipClusters: "presetHandle": "bytes", }, }, - 0x00000007: { - "commandId": 0x00000007, - "commandName": "StartPresetsSchedulesEditRequest", - "args": { - "timeoutSeconds": "int", - }, - }, - 0x00000008: { - "commandId": 0x00000008, - "commandName": "CancelPresetsSchedulesEditRequest", - "args": { - }, - }, - 0x00000009: { - "commandId": 0x00000009, - "commandName": "CommitPresetsSchedulesRequest", + 0x000000FE: { + "commandId": 0x000000FE, + "commandName": "AtomicRequest", "args": { + "requestType": "int", + "attributeRequests": "int", + "timeout": "int", }, }, }, @@ -9290,14 +9280,8 @@ class ChipClusters: "writable": True, }, 0x00000052: { - "attributeName": "PresetsSchedulesEditable", - "attributeId": 0x00000052, - "type": "bool", - "reportable": True, - }, - 0x00000053: { "attributeName": "SetpointHoldExpiryTimestamp", - "attributeId": 0x00000053, + "attributeId": 0x00000052, "type": "int", "reportable": True, }, diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 72364de4be6410..ec5928318d97e7 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -140,6 +140,16 @@ class AreaTypeTag(MatterIntEnum): # enum value. This specific value should never be transmitted. kUnknownEnumValue = 95, + class AtomicRequestTypeEnum(MatterIntEnum): + kBeginWrite = 0x00 + kCommitWrite = 0x01 + kRollbackWrite = 0x02 + # All received enum values that are not listed above will be mapped + # to kUnknownEnumValue. This is a helper enum value that should only + # be used by code to process how it handles receiving an unknown + # enum value. This specific value should never be transmitted. + kUnknownEnumValue = 3, + class FloorSurfaceTag(MatterIntEnum): kCarpet = 0x00 kCeramic = 0x01 @@ -296,6 +306,19 @@ def descriptor(cls) -> ClusterObjectDescriptor: floorNumber: 'typing.Union[Nullable, int]' = NullValue areaType: 'typing.Union[Nullable, Globals.Enums.AreaTypeTag]' = NullValue + @dataclass + class AtomicAttributeStatusStruct(ClusterObject): + @ChipUtility.classproperty + def descriptor(cls) -> ClusterObjectDescriptor: + return ClusterObjectDescriptor( + Fields=[ + ClusterObjectFieldDescriptor(Label="attributeID", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="statusCode", Tag=1, Type=uint), + ]) + + attributeID: 'uint' = 0 + statusCode: 'uint' = 0 + @dataclass @@ -32423,8 +32446,7 @@ def descriptor(cls) -> ClusterObjectDescriptor: ClusterObjectFieldDescriptor(Label="activeScheduleHandle", Tag=0x0000004F, Type=typing.Union[None, Nullable, bytes]), ClusterObjectFieldDescriptor(Label="presets", Tag=0x00000050, Type=typing.Optional[typing.List[Thermostat.Structs.PresetStruct]]), ClusterObjectFieldDescriptor(Label="schedules", Tag=0x00000051, Type=typing.Optional[typing.List[Thermostat.Structs.ScheduleStruct]]), - ClusterObjectFieldDescriptor(Label="presetsSchedulesEditable", Tag=0x00000052, Type=typing.Optional[bool]), - ClusterObjectFieldDescriptor(Label="setpointHoldExpiryTimestamp", Tag=0x00000053, Type=typing.Union[None, Nullable, uint]), + ClusterObjectFieldDescriptor(Label="setpointHoldExpiryTimestamp", Tag=0x00000052, Type=typing.Union[None, Nullable, uint]), ClusterObjectFieldDescriptor(Label="generatedCommandList", Tag=0x0000FFF8, Type=typing.List[uint]), ClusterObjectFieldDescriptor(Label="acceptedCommandList", Tag=0x0000FFF9, Type=typing.List[uint]), ClusterObjectFieldDescriptor(Label="eventList", Tag=0x0000FFFA, Type=typing.List[uint]), @@ -32492,7 +32514,6 @@ def descriptor(cls) -> ClusterObjectDescriptor: activeScheduleHandle: 'typing.Union[None, Nullable, bytes]' = None presets: 'typing.Optional[typing.List[Thermostat.Structs.PresetStruct]]' = None schedules: 'typing.Optional[typing.List[Thermostat.Structs.ScheduleStruct]]' = None - presetsSchedulesEditable: 'typing.Optional[bool]' = None setpointHoldExpiryTimestamp: 'typing.Union[None, Nullable, uint]' = None generatedCommandList: 'typing.List[uint]' = None acceptedCommandList: 'typing.List[uint]' = None @@ -32570,7 +32591,6 @@ class ControlSequenceOfOperationEnum(MatterIntEnum): kUnknownEnumValue = 6, class PresetScenarioEnum(MatterIntEnum): - kUnspecified = 0x00 kOccupied = 0x01 kUnoccupied = 0x02 kSleep = 0x03 @@ -32582,7 +32602,7 @@ class PresetScenarioEnum(MatterIntEnum): # to kUnknownEnumValue. This is a helper enum value that should only # be used by code to process how it handles receiving an unknown # enum value. This specific value should never be transmitted. - kUnknownEnumValue = 7, + kUnknownEnumValue = 0, class SetpointChangeSourceEnum(MatterIntEnum): kManual = 0x00 @@ -32671,7 +32691,6 @@ class Feature(IntFlag): kLocalTemperatureNotExposed = 0x40 kMatterScheduleConfiguration = 0x80 kPresets = 0x100 - kSetpoints = 0x200 class HVACSystemTypeBitmap(IntFlag): kCoolingStage = 0x3 @@ -32679,6 +32698,9 @@ class HVACSystemTypeBitmap(IntFlag): kHeatingIsHeatPump = 0x10 kHeatingUsesFuel = 0x20 + class OccupancyBitmap(IntFlag): + kOccupied = 0x1 + class PresetTypeFeaturesBitmap(IntFlag): kAutomatic = 0x1 kSupportsNames = 0x2 @@ -32755,7 +32777,7 @@ def descriptor(cls) -> ClusterObjectDescriptor: ClusterObjectFieldDescriptor(Label="name", Tag=2, Type=typing.Optional[str]), ClusterObjectFieldDescriptor(Label="presetHandle", Tag=3, Type=typing.Optional[bytes]), ClusterObjectFieldDescriptor(Label="transitions", Tag=4, Type=typing.List[Thermostat.Structs.ScheduleTransitionStruct]), - ClusterObjectFieldDescriptor(Label="builtIn", Tag=5, Type=typing.Union[None, Nullable, bool]), + ClusterObjectFieldDescriptor(Label="builtIn", Tag=5, Type=typing.Union[Nullable, bool]), ]) scheduleHandle: 'typing.Union[Nullable, bytes]' = NullValue @@ -32763,7 +32785,7 @@ def descriptor(cls) -> ClusterObjectDescriptor: name: 'typing.Optional[str]' = None presetHandle: 'typing.Optional[bytes]' = None transitions: 'typing.List[Thermostat.Structs.ScheduleTransitionStruct]' = field(default_factory=lambda: []) - builtIn: 'typing.Union[None, Nullable, bool]' = None + builtIn: 'typing.Union[Nullable, bool]' = NullValue @dataclass class PresetStruct(ClusterObject): @@ -32958,46 +32980,44 @@ def descriptor(cls) -> ClusterObjectDescriptor: presetHandle: 'bytes' = b"" @dataclass - class StartPresetsSchedulesEditRequest(ClusterCommand): + class AtomicResponse(ClusterCommand): cluster_id: typing.ClassVar[int] = 0x00000201 - command_id: typing.ClassVar[int] = 0x00000007 - is_client: typing.ClassVar[bool] = True + command_id: typing.ClassVar[int] = 0x000000FD + is_client: typing.ClassVar[bool] = False response_type: typing.ClassVar[str] = None @ChipUtility.classproperty def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="timeoutSeconds", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="statusCode", Tag=0, Type=uint), + ClusterObjectFieldDescriptor(Label="attributeStatus", Tag=1, Type=typing.List[Globals.Structs.AtomicAttributeStatusStruct]), + ClusterObjectFieldDescriptor(Label="timeout", Tag=2, Type=typing.Optional[uint]), ]) - timeoutSeconds: 'uint' = 0 + statusCode: 'uint' = 0 + attributeStatus: 'typing.List[Globals.Structs.AtomicAttributeStatusStruct]' = field(default_factory=lambda: []) + timeout: 'typing.Optional[uint]' = None @dataclass - class CancelPresetsSchedulesEditRequest(ClusterCommand): + class AtomicRequest(ClusterCommand): cluster_id: typing.ClassVar[int] = 0x00000201 - command_id: typing.ClassVar[int] = 0x00000008 + command_id: typing.ClassVar[int] = 0x000000FE is_client: typing.ClassVar[bool] = True - response_type: typing.ClassVar[str] = None + response_type: typing.ClassVar[str] = 'AtomicResponse' @ChipUtility.classproperty def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ + ClusterObjectFieldDescriptor(Label="requestType", Tag=0, Type=Globals.Enums.AtomicRequestTypeEnum), + ClusterObjectFieldDescriptor(Label="attributeRequests", Tag=1, Type=typing.List[uint]), + ClusterObjectFieldDescriptor(Label="timeout", Tag=2, Type=typing.Optional[uint]), ]) - @dataclass - class CommitPresetsSchedulesRequest(ClusterCommand): - cluster_id: typing.ClassVar[int] = 0x00000201 - command_id: typing.ClassVar[int] = 0x00000009 - is_client: typing.ClassVar[bool] = True - response_type: typing.ClassVar[str] = None - - @ChipUtility.classproperty - def descriptor(cls) -> ClusterObjectDescriptor: - return ClusterObjectDescriptor( - Fields=[ - ]) + requestType: 'Globals.Enums.AtomicRequestTypeEnum' = 0 + attributeRequests: 'typing.List[uint]' = field(default_factory=lambda: []) + timeout: 'typing.Optional[uint]' = None class Attributes: @dataclass @@ -33944,22 +33964,6 @@ def attribute_type(cls) -> ClusterObjectFieldDescriptor: value: 'typing.Optional[typing.List[Thermostat.Structs.ScheduleStruct]]' = None - @dataclass - class PresetsSchedulesEditable(ClusterAttributeDescriptor): - @ChipUtility.classproperty - def cluster_id(cls) -> int: - return 0x00000201 - - @ChipUtility.classproperty - def attribute_id(cls) -> int: - return 0x00000052 - - @ChipUtility.classproperty - def attribute_type(cls) -> ClusterObjectFieldDescriptor: - return ClusterObjectFieldDescriptor(Type=typing.Optional[bool]) - - value: 'typing.Optional[bool]' = None - @dataclass class SetpointHoldExpiryTimestamp(ClusterAttributeDescriptor): @ChipUtility.classproperty @@ -33968,7 +33972,7 @@ def cluster_id(cls) -> int: @ChipUtility.classproperty def attribute_id(cls) -> int: - return 0x00000053 + return 0x00000052 @ChipUtility.classproperty def attribute_type(cls) -> ClusterObjectFieldDescriptor: diff --git a/src/controller/python/chip/clusters/__init__.py b/src/controller/python/chip/clusters/__init__.py index 5fbb13dcc616a9..b135345e9657de 100644 --- a/src/controller/python/chip/clusters/__init__.py +++ b/src/controller/python/chip/clusters/__init__.py @@ -32,7 +32,7 @@ EcosystemInformation, ElectricalEnergyMeasurement, ElectricalMeasurement, ElectricalPowerMeasurement, EnergyEvse, EnergyEvseMode, EnergyPreference, EthernetNetworkDiagnostics, FanControl, FaultInjection, FixedLabel, FlowMeasurement, FormaldehydeConcentrationMeasurement, GeneralCommissioning, GeneralDiagnostics, - GroupKeyManagement, Groups, HepaFilterMonitoring, IcdManagement, Identify, IlluminanceMeasurement, + Globals, GroupKeyManagement, Groups, HepaFilterMonitoring, IcdManagement, Identify, IlluminanceMeasurement, KeypadInput, LaundryDryerControls, LaundryWasherControls, LaundryWasherMode, LevelControl, LocalizationConfiguration, LowPower, MediaInput, MediaPlayback, MicrowaveOvenControl, MicrowaveOvenMode, ModeSelect, NetworkCommissioning, NitrogenDioxideConcentrationMeasurement, OccupancySensing, OnOff, @@ -56,7 +56,7 @@ ContentControl, ContentLauncher, DemandResponseLoadControl, Descriptor, DeviceEnergyManagementMode, DeviceEnergyManagement, DeviceEnergyManagementMode, DiagnosticLogs, DishwasherAlarm, DishwasherMode, DoorLock, EcosystemInformation, ElectricalEnergyMeasurement, ElectricalMeasurement, ElectricalPowerMeasurement, EnergyEvse, EnergyEvseMode, EnergyPreference, EthernetNetworkDiagnostics, FanControl, FaultInjection, FixedLabel, FlowMeasurement, - FormaldehydeConcentrationMeasurement, GeneralCommissioning, GeneralDiagnostics, GroupKeyManagement, Groups, + FormaldehydeConcentrationMeasurement, GeneralCommissioning, GeneralDiagnostics, Globals, GroupKeyManagement, Groups, HepaFilterMonitoring, IcdManagement, Identify, IlluminanceMeasurement, KeypadInput, LaundryDryerControls, LaundryWasherControls, LaundryWasherMode, LevelControl, LocalizationConfiguration, LowPower, MediaInput, MediaPlayback, MicrowaveOvenControl, MicrowaveOvenMode, ModeSelect, NetworkCommissioning, NitrogenDioxideConcentrationMeasurement, diff --git a/src/darwin/Framework/CHIP/templates/availability.yaml b/src/darwin/Framework/CHIP/templates/availability.yaml index ee6351b3c6793e..507e19eae032d9 100644 --- a/src/darwin/Framework/CHIP/templates/availability.yaml +++ b/src/darwin/Framework/CHIP/templates/availability.yaml @@ -9580,7 +9580,6 @@ - ActivePresetHandle - Presets - Schedules - - PresetsSchedulesEditable - TemperatureSetpointHoldPolicy - SetpointHoldExpiryTimestamp - ActiveScheduleHandle diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm index ce8cbd7a5621f0..06aa9c017be027 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeSpecifiedCheck.mm @@ -4179,9 +4179,6 @@ static BOOL AttributeIsSpecifiedInThermostatCluster(AttributeId aAttributeId) case Attributes::Schedules::Id: { return YES; } - case Attributes::PresetsSchedulesEditable::Id: { - return YES; - } case Attributes::SetpointHoldExpiryTimestamp::Id: { return YES; } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm index 2a2cf4f84cb44d..b1c3fb9d486ca5 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm @@ -11779,7 +11779,7 @@ static id _Nullable DecodeAttributeValueForThermostatCluster(AttributeId aAttrib return nil; } NSNumber * _Nonnull value; - value = [NSNumber numberWithUnsignedChar:cppValue]; + value = [NSNumber numberWithUnsignedChar:cppValue.Raw()]; return value; } case Attributes::AbsMinHeatSetpointLimit::Id: { @@ -11856,7 +11856,7 @@ static id _Nullable DecodeAttributeValueForThermostatCluster(AttributeId aAttrib return nil; } NSNumber * _Nonnull value; - value = [NSNumber numberWithUnsignedChar:cppValue]; + value = [NSNumber numberWithUnsignedChar:cppValue.Raw()]; return value; } case Attributes::LocalTemperatureCalibration::Id: { @@ -12595,14 +12595,10 @@ static id _Nullable DecodeAttributeValueForThermostatCluster(AttributeId aAttrib } newElement_0.transitions = array_2; } - if (entry_0.builtIn.HasValue()) { - if (entry_0.builtIn.Value().IsNull()) { - newElement_0.builtIn = nil; - } else { - newElement_0.builtIn = [NSNumber numberWithBool:entry_0.builtIn.Value().Value()]; - } - } else { + if (entry_0.builtIn.IsNull()) { newElement_0.builtIn = nil; + } else { + newElement_0.builtIn = [NSNumber numberWithBool:entry_0.builtIn.Value()]; } [array_0 addObject:newElement_0]; } @@ -12615,17 +12611,6 @@ static id _Nullable DecodeAttributeValueForThermostatCluster(AttributeId aAttrib } return value; } - case Attributes::PresetsSchedulesEditable::Id: { - using TypeInfo = Attributes::PresetsSchedulesEditable::TypeInfo; - TypeInfo::DecodableType cppValue; - *aError = DataModel::Decode(aReader, cppValue); - if (*aError != CHIP_NO_ERROR) { - return nil; - } - NSNumber * _Nonnull value; - value = [NSNumber numberWithBool:cppValue]; - return value; - } case Attributes::SetpointHoldExpiryTimestamp::Id: { using TypeInfo = Attributes::SetpointHoldExpiryTimestamp::TypeInfo; TypeInfo::DecodableType cppValue; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index fe78478449ad36..21b7a81cb5746f 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -10017,25 +10017,25 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) /** * Command SetpointRaiseLower * - * Command description for SetpointRaiseLower + * Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ - (void)setpointRaiseLowerWithParams:(MTRThermostatClusterSetpointRaiseLowerParams *)params completion:(MTRStatusCompletion)completion MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); /** * Command SetWeeklySchedule * - * Command description for SetWeeklySchedule + * This command is used to update the thermostat weekly setpoint schedule from a management system. */ - (void)setWeeklyScheduleWithParams:(MTRThermostatClusterSetWeeklyScheduleParams *)params completion:(MTRStatusCompletion)completion MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); /** * Command GetWeeklySchedule * - * Command description for GetWeeklySchedule + * The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ - (void)getWeeklyScheduleWithParams:(MTRThermostatClusterGetWeeklyScheduleParams *)params completion:(void (^)(MTRThermostatClusterGetWeeklyScheduleResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); /** * Command ClearWeeklySchedule * - * This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. + * This command is used to clear the weekly schedule. */ - (void)clearWeeklyScheduleWithParams:(MTRThermostatClusterClearWeeklyScheduleParams * _Nullable)params completion:(MTRStatusCompletion)completion MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); - (void)clearWeeklyScheduleWithCompletion:(MTRStatusCompletion)completion @@ -10043,37 +10043,21 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) /** * Command SetActiveScheduleRequest * - * This command is used to set the active schedule. + * Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ - (void)setActiveScheduleRequestWithParams:(MTRThermostatClusterSetActiveScheduleRequestParams *)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; /** * Command SetActivePresetRequest * - * This command is used to set the active preset. + * ID */ - (void)setActivePresetRequestWithParams:(MTRThermostatClusterSetActivePresetRequestParams *)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; /** - * Command StartPresetsSchedulesEditRequest + * Command AtomicRequest * - * This command is used to start editing the presets and schedules. + * Begins, Commits or Cancels an atomic write */ -- (void)startPresetsSchedulesEditRequestWithParams:(MTRThermostatClusterStartPresetsSchedulesEditRequestParams *)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -/** - * Command CancelPresetsSchedulesEditRequest - * - * This command is used to cancel editing presets and schedules. - */ -- (void)cancelPresetsSchedulesEditRequestWithParams:(MTRThermostatClusterCancelPresetsSchedulesEditRequestParams * _Nullable)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)cancelPresetsSchedulesEditRequestWithCompletion:(MTRStatusCompletion)completion - MTR_PROVISIONALLY_AVAILABLE; -/** - * Command CommitPresetsSchedulesRequest - * - * This command is used to notify the server that all edits are done and should be committed. - */ -- (void)commitPresetsSchedulesRequestWithParams:(MTRThermostatClusterCommitPresetsSchedulesRequestParams * _Nullable)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)commitPresetsSchedulesRequestWithCompletion:(MTRStatusCompletion)completion - MTR_PROVISIONALLY_AVAILABLE; +- (void)atomicRequestWithParams:(MTRThermostatClusterAtomicRequestParams *)params completion:(void (^)(MTRThermostatClusterAtomicResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)readAttributeLocalTemperatureWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); - (void)subscribeAttributeLocalTemperatureWithParams:(MTRSubscribeParams *)params @@ -10487,12 +10471,6 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) reportHandler:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; + (void)readAttributeSchedulesWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSArray * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)readAttributePresetsSchedulesEditableWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; -- (void)subscribeAttributePresetsSchedulesEditableWithParams:(MTRSubscribeParams *)params - subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler MTR_PROVISIONALLY_AVAILABLE; -+ (void)readAttributePresetsSchedulesEditableWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - - (void)readAttributeSetpointHoldExpiryTimestampWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (void)subscribeAttributeSetpointHoldExpiryTimestampWithParams:(MTRSubscribeParams *)params subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished @@ -17308,6 +17286,12 @@ typedef NS_ENUM(uint8_t, MTRDataTypeAreaTypeTag) { MTRDataTypeAreaTypeTagWorkshop MTR_PROVISIONALLY_AVAILABLE = 0x5E, } MTR_PROVISIONALLY_AVAILABLE; +typedef NS_ENUM(uint8_t, MTRDataTypeAtomicRequestTypeEnum) { + MTRDataTypeAtomicRequestTypeEnumBeginWrite MTR_PROVISIONALLY_AVAILABLE = 0x00, + MTRDataTypeAtomicRequestTypeEnumCommitWrite MTR_PROVISIONALLY_AVAILABLE = 0x01, + MTRDataTypeAtomicRequestTypeEnumRollbackWrite MTR_PROVISIONALLY_AVAILABLE = 0x02, +} MTR_PROVISIONALLY_AVAILABLE; + typedef NS_ENUM(uint8_t, MTRDataTypeFloorSurfaceTag) { MTRDataTypeFloorSurfaceTagCarpet MTR_PROVISIONALLY_AVAILABLE = 0x00, MTRDataTypeFloorSurfaceTagCeramic MTR_PROVISIONALLY_AVAILABLE = 0x01, @@ -19951,7 +19935,6 @@ typedef NS_ENUM(uint8_t, MTRThermostatControlSequence) { } MTR_DEPRECATED("Please use MTRThermostatControlSequenceOfOperation", ios(16.1, 17.4), macos(13.0, 14.4), watchos(9.1, 10.4), tvos(16.1, 17.4)); typedef NS_ENUM(uint8_t, MTRThermostatPresetScenario) { - MTRThermostatPresetScenarioUnspecified MTR_PROVISIONALLY_AVAILABLE = 0x00, MTRThermostatPresetScenarioOccupied MTR_PROVISIONALLY_AVAILABLE = 0x01, MTRThermostatPresetScenarioUnoccupied MTR_PROVISIONALLY_AVAILABLE = 0x02, MTRThermostatPresetScenarioSleep MTR_PROVISIONALLY_AVAILABLE = 0x03, @@ -20036,7 +20019,6 @@ typedef NS_OPTIONS(uint32_t, MTRThermostatFeature) { MTRThermostatFeatureLocalTemperatureNotExposed MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) = 0x40, MTRThermostatFeatureMatterScheduleConfiguration MTR_PROVISIONALLY_AVAILABLE = 0x80, MTRThermostatFeaturePresets MTR_PROVISIONALLY_AVAILABLE = 0x100, - MTRThermostatFeatureSetpoints MTR_PROVISIONALLY_AVAILABLE = 0x200, } MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); typedef NS_OPTIONS(uint8_t, MTRThermostatHVACSystemTypeBitmap) { @@ -20046,6 +20028,10 @@ typedef NS_OPTIONS(uint8_t, MTRThermostatHVACSystemTypeBitmap) { MTRThermostatHVACSystemTypeBitmapHeatingUsesFuel MTR_PROVISIONALLY_AVAILABLE = 0x20, } MTR_PROVISIONALLY_AVAILABLE; +typedef NS_OPTIONS(uint8_t, MTRThermostatOccupancyBitmap) { + MTRThermostatOccupancyBitmapOccupied MTR_PROVISIONALLY_AVAILABLE = 0x1, +} MTR_PROVISIONALLY_AVAILABLE; + typedef NS_OPTIONS(uint16_t, MTRThermostatPresetTypeFeaturesBitmap) { MTRThermostatPresetTypeFeaturesBitmapAutomatic MTR_PROVISIONALLY_AVAILABLE = 0x1, MTRThermostatPresetTypeFeaturesBitmapSupportsNames MTR_PROVISIONALLY_AVAILABLE = 0x2, diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm index 7a94c0954e1683..2cd1653c867faa 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm @@ -68194,83 +68194,27 @@ - (void)setActivePresetRequestWithParams:(MTRThermostatClusterSetActivePresetReq queue:self.callbackQueue completion:responseHandler]; } -- (void)startPresetsSchedulesEditRequestWithParams:(MTRThermostatClusterStartPresetsSchedulesEditRequestParams *)params completion:(MTRStatusCompletion)completion +- (void)atomicRequestWithParams:(MTRThermostatClusterAtomicRequestParams *)params completion:(void (^)(MTRThermostatClusterAtomicResponseParams * _Nullable data, NSError * _Nullable error))completion { if (params == nil) { - params = [[MTRThermostatClusterStartPresetsSchedulesEditRequestParams + params = [[MTRThermostatClusterAtomicRequestParams alloc] init]; } auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { - completion(error); - }; - - auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; - - using RequestType = Thermostat::Commands::StartPresetsSchedulesEditRequest::Type; - [self.device _invokeKnownCommandWithEndpointID:self.endpointID - clusterID:@(RequestType::GetClusterId()) - commandID:@(RequestType::GetCommandId()) - commandPayload:params - timedInvokeTimeout:timedInvokeTimeoutMs - serverSideProcessingTimeout:params.serverSideProcessingTimeout - responseClass:nil - queue:self.callbackQueue - completion:responseHandler]; -} -- (void)cancelPresetsSchedulesEditRequestWithCompletion:(MTRStatusCompletion)completion -{ - [self cancelPresetsSchedulesEditRequestWithParams:nil completion:completion]; -} -- (void)cancelPresetsSchedulesEditRequestWithParams:(MTRThermostatClusterCancelPresetsSchedulesEditRequestParams * _Nullable)params completion:(MTRStatusCompletion)completion -{ - if (params == nil) { - params = [[MTRThermostatClusterCancelPresetsSchedulesEditRequestParams - alloc] init]; - } - - auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { - completion(error); - }; - - auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; - - using RequestType = Thermostat::Commands::CancelPresetsSchedulesEditRequest::Type; - [self.device _invokeKnownCommandWithEndpointID:self.endpointID - clusterID:@(RequestType::GetClusterId()) - commandID:@(RequestType::GetCommandId()) - commandPayload:params - timedInvokeTimeout:timedInvokeTimeoutMs - serverSideProcessingTimeout:params.serverSideProcessingTimeout - responseClass:nil - queue:self.callbackQueue - completion:responseHandler]; -} -- (void)commitPresetsSchedulesRequestWithCompletion:(MTRStatusCompletion)completion -{ - [self commitPresetsSchedulesRequestWithParams:nil completion:completion]; -} -- (void)commitPresetsSchedulesRequestWithParams:(MTRThermostatClusterCommitPresetsSchedulesRequestParams * _Nullable)params completion:(MTRStatusCompletion)completion -{ - if (params == nil) { - params = [[MTRThermostatClusterCommitPresetsSchedulesRequestParams - alloc] init]; - } - - auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { - completion(error); + completion(response, error); }; auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; - using RequestType = Thermostat::Commands::CommitPresetsSchedulesRequest::Type; + using RequestType = Thermostat::Commands::AtomicRequest::Type; [self.device _invokeKnownCommandWithEndpointID:self.endpointID clusterID:@(RequestType::GetClusterId()) commandID:@(RequestType::GetCommandId()) commandPayload:params timedInvokeTimeout:timedInvokeTimeoutMs serverSideProcessingTimeout:params.serverSideProcessingTimeout - responseClass:nil + responseClass:MTRThermostatClusterAtomicResponseParams.class queue:self.callbackQueue completion:responseHandler]; } @@ -68631,7 +68575,7 @@ - (void)writeAttributeHVACSystemTypeConfigurationWithValue:(NSNumber * _Nonnull) ListFreer listFreer; using TypeInfo = Thermostat::Attributes::HVACSystemTypeConfiguration::TypeInfo; TypeInfo::Type cppValue; - cppValue = value.unsignedCharValue; + cppValue = static_cast>(value.unsignedCharValue); chip::Controller::ClusterBase cppCluster(exchangeManager, session, self.endpointID.unsignedShortValue); return cppCluster.WriteAttribute(cppValue, bridge, successCb, failureCb, timedWriteTimeout); }); @@ -71313,15 +71257,12 @@ - (void)writeAttributeSchedulesWithValue:(NSArray * _Nonnull)value params:(MTRWr listHolder_0->mList[i_0].transitions = ListType_2(); } } - if (element_0.builtIn != nil) { - auto & definedValue_2 = listHolder_0->mList[i_0].builtIn.Emplace(); - if (element_0.builtIn == nil) { - definedValue_2.SetNull(); - } else { - auto & nonNullValue_3 = definedValue_2.SetNonNull(); - nonNullValue_3 = element_0.builtIn.boolValue; + if (element_0.builtIn == nil) { + listHolder_0->mList[i_0].builtIn.SetNull(); + } else { + auto & nonNullValue_2 = listHolder_0->mList[i_0].builtIn.SetNonNull(); + nonNullValue_2 = element_0.builtIn.boolValue; } - } } cppValue = ListType_0(listHolder_0->mList, value.count); } else { @@ -71359,42 +71300,6 @@ + (void)readAttributeSchedulesWithClusterStateCache:(MTRClusterStateCacheContain completion:completion]; } -- (void)readAttributePresetsSchedulesEditableWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion -{ - using TypeInfo = Thermostat::Attributes::PresetsSchedulesEditable::TypeInfo; - [self.device _readKnownAttributeWithEndpointID:self.endpointID - clusterID:@(TypeInfo::GetClusterId()) - attributeID:@(TypeInfo::GetAttributeId()) - params:nil - queue:self.callbackQueue - completion:completion]; -} - -- (void)subscribeAttributePresetsSchedulesEditableWithParams:(MTRSubscribeParams * _Nonnull)params - subscriptionEstablished:(MTRSubscriptionEstablishedHandler _Nullable)subscriptionEstablished - reportHandler:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))reportHandler -{ - using TypeInfo = Thermostat::Attributes::PresetsSchedulesEditable::TypeInfo; - [self.device _subscribeToKnownAttributeWithEndpointID:self.endpointID - clusterID:@(TypeInfo::GetClusterId()) - attributeID:@(TypeInfo::GetAttributeId()) - params:params - queue:self.callbackQueue - reportHandler:reportHandler - subscriptionEstablished:subscriptionEstablished]; -} - -+ (void)readAttributePresetsSchedulesEditableWithClusterStateCache:(MTRClusterStateCacheContainer *)clusterStateCacheContainer endpoint:(NSNumber *)endpoint queue:(dispatch_queue_t)queue completion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion -{ - using TypeInfo = Thermostat::Attributes::PresetsSchedulesEditable::TypeInfo; - [clusterStateCacheContainer - _readKnownCachedAttributeWithEndpointID:static_cast([endpoint unsignedShortValue]) - clusterID:TypeInfo::GetClusterId() - attributeID:TypeInfo::GetAttributeId() - queue:queue - completion:completion]; -} - - (void)readAttributeSetpointHoldExpiryTimestampWithCompletion:(void (^)(NSNumber * _Nullable value, NSError * _Nullable error))completion { using TypeInfo = Thermostat::Attributes::SetpointHoldExpiryTimestamp::TypeInfo; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h index 36ba74c1b9867a..aa1973220085ec 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterConstants.h @@ -3493,8 +3493,7 @@ typedef NS_ENUM(uint32_t, MTRAttributeIDType) { MTRAttributeIDTypeClusterThermostatAttributeActiveScheduleHandleID MTR_PROVISIONALLY_AVAILABLE = 0x0000004F, MTRAttributeIDTypeClusterThermostatAttributePresetsID MTR_PROVISIONALLY_AVAILABLE = 0x00000050, MTRAttributeIDTypeClusterThermostatAttributeSchedulesID MTR_PROVISIONALLY_AVAILABLE = 0x00000051, - MTRAttributeIDTypeClusterThermostatAttributePresetsSchedulesEditableID MTR_PROVISIONALLY_AVAILABLE = 0x00000052, - MTRAttributeIDTypeClusterThermostatAttributeSetpointHoldExpiryTimestampID MTR_PROVISIONALLY_AVAILABLE = 0x00000053, + MTRAttributeIDTypeClusterThermostatAttributeSetpointHoldExpiryTimestampID MTR_PROVISIONALLY_AVAILABLE = 0x00000052, MTRAttributeIDTypeClusterThermostatAttributeGeneratedCommandListID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = MTRAttributeIDTypeGlobalAttributeGeneratedCommandListID, MTRAttributeIDTypeClusterThermostatAttributeAcceptedCommandListID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = MTRAttributeIDTypeGlobalAttributeAcceptedCommandListID, MTRAttributeIDTypeClusterThermostatAttributeEventListID MTR_PROVISIONALLY_AVAILABLE = MTRAttributeIDTypeGlobalAttributeEventListID, @@ -6625,9 +6624,8 @@ typedef NS_ENUM(uint32_t, MTRCommandIDType) { MTRCommandIDTypeClusterThermostatCommandClearWeeklyScheduleID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) = 0x00000003, MTRCommandIDTypeClusterThermostatCommandSetActiveScheduleRequestID MTR_PROVISIONALLY_AVAILABLE = 0x00000005, MTRCommandIDTypeClusterThermostatCommandSetActivePresetRequestID MTR_PROVISIONALLY_AVAILABLE = 0x00000006, - MTRCommandIDTypeClusterThermostatCommandStartPresetsSchedulesEditRequestID MTR_PROVISIONALLY_AVAILABLE = 0x00000007, - MTRCommandIDTypeClusterThermostatCommandCancelPresetsSchedulesEditRequestID MTR_PROVISIONALLY_AVAILABLE = 0x00000008, - MTRCommandIDTypeClusterThermostatCommandCommitPresetsSchedulesRequestID MTR_PROVISIONALLY_AVAILABLE = 0x00000009, + MTRCommandIDTypeClusterThermostatCommandAtomicResponseID MTR_PROVISIONALLY_AVAILABLE = 0x000000FD, + MTRCommandIDTypeClusterThermostatCommandAtomicRequestID MTR_PROVISIONALLY_AVAILABLE = 0x000000FE, // Cluster FanControl deprecated command id names diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm index d7c40ca085b628..3383cab3cec1aa 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusterNames.mm @@ -5872,10 +5872,6 @@ result = @"Schedules"; break; - case MTRAttributeIDTypeClusterThermostatAttributePresetsSchedulesEditableID: - result = @"PresetsSchedulesEditable"; - break; - case MTRAttributeIDTypeClusterThermostatAttributeSetpointHoldExpiryTimestampID: result = @"SetpointHoldExpiryTimestamp"; break; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h index 373a873d859389..6b441121b72413 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.h @@ -4661,13 +4661,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); - (void)setActiveScheduleRequestWithParams:(MTRThermostatClusterSetActiveScheduleRequestParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; - (void)setActivePresetRequestWithParams:(MTRThermostatClusterSetActivePresetRequestParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)startPresetsSchedulesEditRequestWithParams:(MTRThermostatClusterStartPresetsSchedulesEditRequestParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)cancelPresetsSchedulesEditRequestWithParams:(MTRThermostatClusterCancelPresetsSchedulesEditRequestParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)cancelPresetsSchedulesEditRequestWithExpectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion - MTR_PROVISIONALLY_AVAILABLE; -- (void)commitPresetsSchedulesRequestWithParams:(MTRThermostatClusterCommitPresetsSchedulesRequestParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; -- (void)commitPresetsSchedulesRequestWithExpectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion - MTR_PROVISIONALLY_AVAILABLE; +- (void)atomicRequestWithParams:(MTRThermostatClusterAtomicRequestParams *)params expectedValues:(NSArray *> * _Nullable)expectedDataValueDictionaries expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRThermostatClusterAtomicResponseParams * _Nullable data, NSError * _Nullable error))completion MTR_PROVISIONALLY_AVAILABLE; - (NSDictionary * _Nullable)readAttributeLocalTemperatureWithParams:(MTRReadParams * _Nullable)params MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); @@ -4845,8 +4839,6 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) - (void)writeAttributeSchedulesWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs MTR_PROVISIONALLY_AVAILABLE; - (void)writeAttributeSchedulesWithValue:(NSDictionary *)dataValueDictionary expectedValueInterval:(NSNumber *)expectedValueIntervalMs params:(MTRWriteParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; -- (NSDictionary * _Nullable)readAttributePresetsSchedulesEditableWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; - - (NSDictionary * _Nullable)readAttributeSetpointHoldExpiryTimestampWithParams:(MTRReadParams * _Nullable)params MTR_PROVISIONALLY_AVAILABLE; - (NSDictionary * _Nullable)readAttributeGeneratedCommandListWithParams:(MTRReadParams * _Nullable)params MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm index d0944234c6fbed..361abcf5698306 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRClusters.mm @@ -13327,82 +13327,20 @@ - (void)setActivePresetRequestWithParams:(MTRThermostatClusterSetActivePresetReq completion:responseHandler]; } -- (void)startPresetsSchedulesEditRequestWithParams:(MTRThermostatClusterStartPresetsSchedulesEditRequestParams *)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion +- (void)atomicRequestWithParams:(MTRThermostatClusterAtomicRequestParams *)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(void (^)(MTRThermostatClusterAtomicResponseParams * _Nullable data, NSError * _Nullable error))completion { if (params == nil) { - params = [[MTRThermostatClusterStartPresetsSchedulesEditRequestParams + params = [[MTRThermostatClusterAtomicRequestParams alloc] init]; } auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { - completion(error); - }; - - auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; - - using RequestType = Thermostat::Commands::StartPresetsSchedulesEditRequest::Type; - [self.device _invokeKnownCommandWithEndpointID:self.endpointID - clusterID:@(RequestType::GetClusterId()) - commandID:@(RequestType::GetCommandId()) - commandPayload:params - expectedValues:expectedValues - expectedValueInterval:expectedValueIntervalMs - timedInvokeTimeout:timedInvokeTimeoutMs - serverSideProcessingTimeout:params.serverSideProcessingTimeout - responseClass:nil - queue:self.callbackQueue - completion:responseHandler]; -} - -- (void)cancelPresetsSchedulesEditRequestWithExpectedValues:(NSArray *> *)expectedValues expectedValueInterval:(NSNumber *)expectedValueIntervalMs completion:(MTRStatusCompletion)completion -{ - [self cancelPresetsSchedulesEditRequestWithParams:nil expectedValues:expectedValues expectedValueInterval:expectedValueIntervalMs completion:completion]; -} -- (void)cancelPresetsSchedulesEditRequestWithParams:(MTRThermostatClusterCancelPresetsSchedulesEditRequestParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion -{ - if (params == nil) { - params = [[MTRThermostatClusterCancelPresetsSchedulesEditRequestParams - alloc] init]; - } - - auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { - completion(error); - }; - - auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; - - using RequestType = Thermostat::Commands::CancelPresetsSchedulesEditRequest::Type; - [self.device _invokeKnownCommandWithEndpointID:self.endpointID - clusterID:@(RequestType::GetClusterId()) - commandID:@(RequestType::GetCommandId()) - commandPayload:params - expectedValues:expectedValues - expectedValueInterval:expectedValueIntervalMs - timedInvokeTimeout:timedInvokeTimeoutMs - serverSideProcessingTimeout:params.serverSideProcessingTimeout - responseClass:nil - queue:self.callbackQueue - completion:responseHandler]; -} - -- (void)commitPresetsSchedulesRequestWithExpectedValues:(NSArray *> *)expectedValues expectedValueInterval:(NSNumber *)expectedValueIntervalMs completion:(MTRStatusCompletion)completion -{ - [self commitPresetsSchedulesRequestWithParams:nil expectedValues:expectedValues expectedValueInterval:expectedValueIntervalMs completion:completion]; -} -- (void)commitPresetsSchedulesRequestWithParams:(MTRThermostatClusterCommitPresetsSchedulesRequestParams * _Nullable)params expectedValues:(NSArray *> * _Nullable)expectedValues expectedValueInterval:(NSNumber * _Nullable)expectedValueIntervalMs completion:(MTRStatusCompletion)completion -{ - if (params == nil) { - params = [[MTRThermostatClusterCommitPresetsSchedulesRequestParams - alloc] init]; - } - - auto responseHandler = ^(id _Nullable response, NSError * _Nullable error) { - completion(error); + completion(response, error); }; auto * timedInvokeTimeoutMs = params.timedInvokeTimeoutMs; - using RequestType = Thermostat::Commands::CommitPresetsSchedulesRequest::Type; + using RequestType = Thermostat::Commands::AtomicRequest::Type; [self.device _invokeKnownCommandWithEndpointID:self.endpointID clusterID:@(RequestType::GetClusterId()) commandID:@(RequestType::GetCommandId()) @@ -13411,7 +13349,7 @@ - (void)commitPresetsSchedulesRequestWithParams:(MTRThermostatClusterCommitPrese expectedValueInterval:expectedValueIntervalMs timedInvokeTimeout:timedInvokeTimeoutMs serverSideProcessingTimeout:params.serverSideProcessingTimeout - responseClass:nil + responseClass:MTRThermostatClusterAtomicResponseParams.class queue:self.callbackQueue completion:responseHandler]; } @@ -14030,11 +13968,6 @@ - (void)writeAttributeSchedulesWithValue:(NSDictionary *)dataVal [self.device writeAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeThermostatID) attributeID:@(MTRAttributeIDTypeClusterThermostatAttributeSchedulesID) value:dataValueDictionary expectedValueInterval:expectedValueIntervalMs timedWriteTimeout:timedWriteTimeout]; } -- (NSDictionary * _Nullable)readAttributePresetsSchedulesEditableWithParams:(MTRReadParams * _Nullable)params -{ - return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeThermostatID) attributeID:@(MTRAttributeIDTypeClusterThermostatAttributePresetsSchedulesEditableID) params:params]; -} - - (NSDictionary * _Nullable)readAttributeSetpointHoldExpiryTimestampWithParams:(MTRReadParams * _Nullable)params { return [self.device readAttributeWithEndpointID:self.endpointID clusterID:@(MTRClusterIDTypeThermostatID) attributeID:@(MTRAttributeIDTypeClusterThermostatAttributeSetpointHoldExpiryTimestampID) params:params]; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index a1255fd62f2d23..88ef499858e1a7 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -7965,65 +7965,36 @@ MTR_PROVISIONALLY_AVAILABLE @end MTR_PROVISIONALLY_AVAILABLE -@interface MTRThermostatClusterStartPresetsSchedulesEditRequestParams : NSObject +@interface MTRThermostatClusterAtomicResponseParams : NSObject -@property (nonatomic, copy) NSNumber * _Nonnull timeoutSeconds MTR_PROVISIONALLY_AVAILABLE; -/** - * Controls whether the command is a timed command (using Timed Invoke). - * - * If nil (the default value), a regular invoke is done for commands that do - * not require a timed invoke and a timed invoke with some default timed request - * timeout is done for commands that require a timed invoke. - * - * If not nil, a timed invoke is done, with the provided value used as the timed - * request timeout. The value should be chosen small enough to provide the - * desired security properties but large enough that it will allow a round-trip - * from the sever to the client (for the status response and actual invoke - * request) within the timeout window. - * - */ -@property (nonatomic, copy, nullable) NSNumber * timedInvokeTimeoutMs; +@property (nonatomic, copy) NSNumber * _Nonnull statusCode MTR_PROVISIONALLY_AVAILABLE; -/** - * Controls how much time, in seconds, we will allow for the server to process the command. - * - * The command will then time out if that much time, plus an allowance for retransmits due to network failures, passes. - * - * If nil, the framework will try to select an appropriate timeout value itself. - */ -@property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; -@end +@property (nonatomic, copy) NSArray * _Nonnull attributeStatus MTR_PROVISIONALLY_AVAILABLE; -MTR_PROVISIONALLY_AVAILABLE -@interface MTRThermostatClusterCancelPresetsSchedulesEditRequestParams : NSObject -/** - * Controls whether the command is a timed command (using Timed Invoke). - * - * If nil (the default value), a regular invoke is done for commands that do - * not require a timed invoke and a timed invoke with some default timed request - * timeout is done for commands that require a timed invoke. - * - * If not nil, a timed invoke is done, with the provided value used as the timed - * request timeout. The value should be chosen small enough to provide the - * desired security properties but large enough that it will allow a round-trip - * from the sever to the client (for the status response and actual invoke - * request) within the timeout window. - * - */ -@property (nonatomic, copy, nullable) NSNumber * timedInvokeTimeoutMs; +@property (nonatomic, copy) NSNumber * _Nullable timeout MTR_PROVISIONALLY_AVAILABLE; /** - * Controls how much time, in seconds, we will allow for the server to process the command. + * Initialize an MTRThermostatClusterAtomicResponseParams with a response-value dictionary + * of the sort that MTRDeviceResponseHandler would receive. * - * The command will then time out if that much time, plus an allowance for retransmits due to network failures, passes. + * Will return nil and hand out an error if the response-value dictionary is not + * a command data response or is not the right command response. * - * If nil, the framework will try to select an appropriate timeout value itself. + * Will return nil and hand out an error if the data response does not match the known + * schema for this command. */ -@property (nonatomic, copy, nullable) NSNumber * serverSideProcessingTimeout; +- (nullable instancetype)initWithResponseValue:(NSDictionary *)responseValue + error:(NSError * __autoreleasing *)error MTR_PROVISIONALLY_AVAILABLE; @end MTR_PROVISIONALLY_AVAILABLE -@interface MTRThermostatClusterCommitPresetsSchedulesRequestParams : NSObject +@interface MTRThermostatClusterAtomicRequestParams : NSObject + +@property (nonatomic, copy) NSNumber * _Nonnull requestType MTR_PROVISIONALLY_AVAILABLE; + +@property (nonatomic, copy) NSArray * _Nonnull attributeRequests MTR_PROVISIONALLY_AVAILABLE; + +@property (nonatomic, copy) NSNumber * _Nullable timeout MTR_PROVISIONALLY_AVAILABLE; /** * Controls whether the command is a timed command (using Timed Invoke). * diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index efeaaa5aa5f50f..70f3cad514818b 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -22803,162 +22803,127 @@ - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader } @end -@implementation MTRThermostatClusterStartPresetsSchedulesEditRequestParams +@implementation MTRThermostatClusterAtomicResponseParams - (instancetype)init { if (self = [super init]) { - _timeoutSeconds = @(0); - _timedInvokeTimeoutMs = nil; - _serverSideProcessingTimeout = nil; + _statusCode = @(0); + + _attributeStatus = [NSArray array]; + + _timeout = nil; } return self; } - (id)copyWithZone:(NSZone * _Nullable)zone; { - auto other = [[MTRThermostatClusterStartPresetsSchedulesEditRequestParams alloc] init]; + auto other = [[MTRThermostatClusterAtomicResponseParams alloc] init]; - other.timeoutSeconds = self.timeoutSeconds; - other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; - other.serverSideProcessingTimeout = self.serverSideProcessingTimeout; + other.statusCode = self.statusCode; + other.attributeStatus = self.attributeStatus; + other.timeout = self.timeout; return other; } - (NSString *)description { - NSString * descriptionString = [NSString stringWithFormat:@"<%@: timeoutSeconds:%@; >", NSStringFromClass([self class]), _timeoutSeconds]; + NSString * descriptionString = [NSString stringWithFormat:@"<%@: statusCode:%@; attributeStatus:%@; timeout:%@; >", NSStringFromClass([self class]), _statusCode, _attributeStatus, _timeout]; return descriptionString; } -@end - -@implementation MTRThermostatClusterStartPresetsSchedulesEditRequestParams (InternalMethods) - -- (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader +- (nullable instancetype)initWithResponseValue:(NSDictionary *)responseValue + error:(NSError * __autoreleasing *)error { - chip::app::Clusters::Thermostat::Commands::StartPresetsSchedulesEditRequest::Type encodableStruct; - ListFreer listFreer; - { - encodableStruct.timeoutSeconds = self.timeoutSeconds.unsignedShortValue; + if (!(self = [super init])) { + return nil; } - auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0); + using DecodableType = chip::app::Clusters::Thermostat::Commands::AtomicResponse::DecodableType; + chip::System::PacketBufferHandle buffer = [MTRBaseDevice _responseDataForCommand:responseValue + clusterID:DecodableType::GetClusterId() + commandID:DecodableType::GetCommandId() + error:error]; if (buffer.IsNull()) { - return CHIP_ERROR_NO_MEMORY; - } - - chip::System::PacketBufferTLVWriter writer; - // Commands never need chained buffers, since they cannot be chunked. - writer.Init(std::move(buffer), /* useChainedBuffers = */ false); - - ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::AnonymousTag(), encodableStruct)); - - ReturnErrorOnFailure(writer.Finalize(&buffer)); - - reader.Init(std::move(buffer)); - return reader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag()); -} - -- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error -{ - chip::System::PacketBufferTLVReader reader; - CHIP_ERROR err = [self _encodeToTLVReader:reader]; - if (err != CHIP_NO_ERROR) { - if (error) { - *error = [MTRError errorForCHIPErrorCode:err]; - } return nil; } - auto decodedObj = MTRDecodeDataValueDictionaryFromCHIPTLV(&reader); - if (decodedObj == nil) { - if (error) { - *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE]; + chip::TLV::TLVReader reader; + reader.Init(buffer->Start(), buffer->DataLength()); + + CHIP_ERROR err = reader.Next(chip::TLV::AnonymousTag()); + if (err == CHIP_NO_ERROR) { + DecodableType decodedStruct; + err = chip::app::DataModel::Decode(reader, decodedStruct); + if (err == CHIP_NO_ERROR) { + err = [self _setFieldsFromDecodableStruct:decodedStruct]; + if (err == CHIP_NO_ERROR) { + return self; + } } } - return decodedObj; -} -@end -@implementation MTRThermostatClusterCancelPresetsSchedulesEditRequestParams -- (instancetype)init -{ - if (self = [super init]) { - _timedInvokeTimeoutMs = nil; - _serverSideProcessingTimeout = nil; + NSString * errorStr = [NSString stringWithFormat:@"Command payload decoding failed: %s", err.AsString()]; + MTR_LOG_ERROR("%s", errorStr.UTF8String); + if (error != nil) { + NSDictionary * userInfo = @{ NSLocalizedFailureReasonErrorKey : NSLocalizedString(errorStr, nil) }; + *error = [NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeSchemaMismatch userInfo:userInfo]; } - return self; -} - -- (id)copyWithZone:(NSZone * _Nullable)zone; -{ - auto other = [[MTRThermostatClusterCancelPresetsSchedulesEditRequestParams alloc] init]; - - other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; - other.serverSideProcessingTimeout = self.serverSideProcessingTimeout; - - return other; -} - -- (NSString *)description -{ - NSString * descriptionString = [NSString stringWithFormat:@"<%@: >", NSStringFromClass([self class])]; - return descriptionString; + return nil; } @end -@implementation MTRThermostatClusterCancelPresetsSchedulesEditRequestParams (InternalMethods) +@implementation MTRThermostatClusterAtomicResponseParams (InternalMethods) -- (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader +- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::Thermostat::Commands::AtomicResponse::DecodableType &)decodableStruct { - chip::app::Clusters::Thermostat::Commands::CancelPresetsSchedulesEditRequest::Type encodableStruct; - ListFreer listFreer; - - auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0); - if (buffer.IsNull()) { - return CHIP_ERROR_NO_MEMORY; + { + self.statusCode = [NSNumber numberWithUnsignedChar:decodableStruct.statusCode]; } - - chip::System::PacketBufferTLVWriter writer; - // Commands never need chained buffers, since they cannot be chunked. - writer.Init(std::move(buffer), /* useChainedBuffers = */ false); - - ReturnErrorOnFailure(chip::app::DataModel::Encode(writer, chip::TLV::AnonymousTag(), encodableStruct)); - - ReturnErrorOnFailure(writer.Finalize(&buffer)); - - reader.Init(std::move(buffer)); - return reader.Next(chip::TLV::kTLVType_Structure, chip::TLV::AnonymousTag()); -} - -- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error -{ - chip::System::PacketBufferTLVReader reader; - CHIP_ERROR err = [self _encodeToTLVReader:reader]; - if (err != CHIP_NO_ERROR) { - if (error) { - *error = [MTRError errorForCHIPErrorCode:err]; + { + { // Scope for our temporary variables + auto * array_0 = [NSMutableArray new]; + auto iter_0 = decodableStruct.attributeStatus.begin(); + while (iter_0.Next()) { + auto & entry_0 = iter_0.GetValue(); + MTRDataTypeAtomicAttributeStatusStruct * newElement_0; + newElement_0 = [MTRDataTypeAtomicAttributeStatusStruct new]; + newElement_0.attributeID = [NSNumber numberWithUnsignedInt:entry_0.attributeID]; + newElement_0.statusCode = [NSNumber numberWithUnsignedChar:entry_0.statusCode]; + [array_0 addObject:newElement_0]; + } + CHIP_ERROR err = iter_0.GetStatus(); + if (err != CHIP_NO_ERROR) { + return err; + } + self.attributeStatus = array_0; } - return nil; } - - auto decodedObj = MTRDecodeDataValueDictionaryFromCHIPTLV(&reader); - if (decodedObj == nil) { - if (error) { - *error = [MTRError errorForCHIPErrorCode:CHIP_ERROR_INCORRECT_STATE]; + { + if (decodableStruct.timeout.HasValue()) { + self.timeout = [NSNumber numberWithUnsignedShort:decodableStruct.timeout.Value()]; + } else { + self.timeout = nil; } } - return decodedObj; + return CHIP_NO_ERROR; } + @end -@implementation MTRThermostatClusterCommitPresetsSchedulesRequestParams +@implementation MTRThermostatClusterAtomicRequestParams - (instancetype)init { if (self = [super init]) { + + _requestType = @(0); + + _attributeRequests = [NSArray array]; + + _timeout = nil; _timedInvokeTimeoutMs = nil; _serverSideProcessingTimeout = nil; } @@ -22967,8 +22932,11 @@ - (instancetype)init - (id)copyWithZone:(NSZone * _Nullable)zone; { - auto other = [[MTRThermostatClusterCommitPresetsSchedulesRequestParams alloc] init]; + auto other = [[MTRThermostatClusterAtomicRequestParams alloc] init]; + other.requestType = self.requestType; + other.attributeRequests = self.attributeRequests; + other.timeout = self.timeout; other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; other.serverSideProcessingTimeout = self.serverSideProcessingTimeout; @@ -22977,18 +22945,51 @@ - (id)copyWithZone:(NSZone * _Nullable)zone; - (NSString *)description { - NSString * descriptionString = [NSString stringWithFormat:@"<%@: >", NSStringFromClass([self class])]; + NSString * descriptionString = [NSString stringWithFormat:@"<%@: requestType:%@; attributeRequests:%@; timeout:%@; >", NSStringFromClass([self class]), _requestType, _attributeRequests, _timeout]; return descriptionString; } @end -@implementation MTRThermostatClusterCommitPresetsSchedulesRequestParams (InternalMethods) +@implementation MTRThermostatClusterAtomicRequestParams (InternalMethods) - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader { - chip::app::Clusters::Thermostat::Commands::CommitPresetsSchedulesRequest::Type encodableStruct; + chip::app::Clusters::Thermostat::Commands::AtomicRequest::Type encodableStruct; ListFreer listFreer; + { + encodableStruct.requestType = static_cast>(self.requestType.unsignedCharValue); + } + { + { + using ListType_0 = std::remove_reference_t; + using ListMemberType_0 = ListMemberTypeGetter::Type; + if (self.attributeRequests.count != 0) { + auto * listHolder_0 = new ListHolder(self.attributeRequests.count); + if (listHolder_0 == nullptr || listHolder_0->mList == nullptr) { + return CHIP_ERROR_INVALID_ARGUMENT; + } + listFreer.add(listHolder_0); + for (size_t i_0 = 0; i_0 < self.attributeRequests.count; ++i_0) { + if (![self.attributeRequests[i_0] isKindOfClass:[NSNumber class]]) { + // Wrong kind of value. + return CHIP_ERROR_INVALID_ARGUMENT; + } + auto element_0 = (NSNumber *) self.attributeRequests[i_0]; + listHolder_0->mList[i_0] = element_0.unsignedIntValue; + } + encodableStruct.attributeRequests = ListType_0(listHolder_0->mList, self.attributeRequests.count); + } else { + encodableStruct.attributeRequests = ListType_0(); + } + } + } + { + if (self.timeout != nil) { + auto & definedValue_0 = encodableStruct.timeout.Emplace(); + definedValue_0 = self.timeout.unsignedShortValue; + } + } auto buffer = chip::System::PacketBufferHandle::New(chip::System::PacketBuffer::kMaxSizeWithoutReserve, 0); if (buffer.IsNull()) { diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h index 4504aefdfc4e91..91e4e865355198 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloads_Internal.h @@ -1498,19 +1498,13 @@ NS_ASSUME_NONNULL_BEGIN @end -@interface MTRThermostatClusterStartPresetsSchedulesEditRequestParams (InternalMethods) +@interface MTRThermostatClusterAtomicResponseParams (InternalMethods) -- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; - -@end - -@interface MTRThermostatClusterCancelPresetsSchedulesEditRequestParams (InternalMethods) - -- (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; +- (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::Thermostat::Commands::AtomicResponse::DecodableType &)decodableStruct; @end -@interface MTRThermostatClusterCommitPresetsSchedulesRequestParams (InternalMethods) +@interface MTRThermostatClusterAtomicRequestParams (InternalMethods) - (NSDictionary * _Nullable)_encodeAsDataValue:(NSError * __autoreleasing *)error; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h index 27d774ef5cc31d..db765a29de8913 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.h @@ -33,6 +33,12 @@ MTR_PROVISIONALLY_AVAILABLE @property (nonatomic, copy) NSNumber * _Nullable areaType MTR_PROVISIONALLY_AVAILABLE; @end +MTR_PROVISIONALLY_AVAILABLE +@interface MTRDataTypeAtomicAttributeStatusStruct : NSObject +@property (nonatomic, copy) NSNumber * _Nonnull attributeID MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy) NSNumber * _Nonnull statusCode MTR_PROVISIONALLY_AVAILABLE; +@end + MTR_AVAILABLE(ios(16.2), macos(13.1), watchos(9.2), tvos(16.2)) @interface MTRDescriptorClusterDeviceTypeStruct : NSObject @property (nonatomic, copy) NSNumber * _Nonnull deviceType MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm index 5821b104376d5a..8bcfc3af65f9a7 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRStructsObjc.mm @@ -85,6 +85,36 @@ - (NSString *)description @end +@implementation MTRDataTypeAtomicAttributeStatusStruct +- (instancetype)init +{ + if (self = [super init]) { + + _attributeID = @(0); + + _statusCode = @(0); + } + return self; +} + +- (id)copyWithZone:(NSZone * _Nullable)zone +{ + auto other = [[MTRDataTypeAtomicAttributeStatusStruct alloc] init]; + + other.attributeID = self.attributeID; + other.statusCode = self.statusCode; + + return other; +} + +- (NSString *)description +{ + NSString * descriptionString = [NSString stringWithFormat:@"<%@: attributeID:%@; statusCode:%@; >", NSStringFromClass([self class]), _attributeID, _statusCode]; + return descriptionString; +} + +@end + @implementation MTRDescriptorClusterDeviceTypeStruct - (instancetype)init { diff --git a/src/python_testing/TC_TSTAT_4_2.py b/src/python_testing/TC_TSTAT_4_2.py index 9a8a8733830cec..513715b7d30f31 100644 --- a/src/python_testing/TC_TSTAT_4_2.py +++ b/src/python_testing/TC_TSTAT_4_2.py @@ -61,32 +61,47 @@ async def write_presets(self, endpoint, presets) -> Status: result = await self.default_controller.WriteAttribute(self.dut_node_id, [(endpoint, cluster.Attributes.Presets(presets))]) return result[0].Status - async def send_edit_preset_request_command(self, - endpoint: int = None, - expected_status: Status = Status.Success): + async def send_edit_atomic_request_begin_command(self, + endpoint: int = None, + expected_status: Status = Status.Success): try: - await self.send_single_cmd(cmd=cluster.Commands.StartPresetsSchedulesEditRequest(timeoutSeconds=180), + await self.send_single_cmd(cmd=cluster.Commands.AtomicRequest(requestType=0, + attributeRequests=[ + cluster.Attributes.Presets.attribute_id], + timeout=1800), endpoint=endpoint) asserts.assert_equal(expected_status, Status.Success) except InteractionModelError as e: asserts.assert_equal(e.status, expected_status, "Unexpected error returned") - async def send_commit_preset_request_command(self, - endpoint: int = None, - expected_status: Status = Status.Success): + async def send_edit_atomic_request_commit_command(self, + endpoint: int = None, + expected_status: Status = Status.Success, + expected_overall_status: Status = Status.Success, + expected_preset_status: Status = Status.Success): try: - await self.send_single_cmd(cmd=cluster.Commands.CommitPresetsSchedulesRequest(), - endpoint=endpoint) - asserts.assert_equal(expected_status, Status.Success) + response = await self.send_single_cmd(cmd=cluster.Commands.AtomicRequest(requestType=1, + attributeRequests=[cluster.Attributes.Presets.attribute_id, cluster.Attributes.Schedules.attribute_id]), + endpoint=endpoint) + asserts.assert_equal(expected_status, Status.Success, "We expected we had a valid commit command") + asserts.assert_equal(response.statusCode, expected_overall_status, "Commit should have the right overall status") + found_preset_status = False + for attrStatus in response.attributeStatus: + if attrStatus.attributeID == cluster.Attributes.Presets.attribute_id: + asserts.assert_equal(attrStatus.statusCode, expected_preset_status, + "Preset attribute commit should have the right status") + found_preset_status = True + asserts.assert_true(found_preset_status, "Preset attribute commit should have a status") except InteractionModelError as e: asserts.assert_equal(e.status, expected_status, "Unexpected error returned") - async def send_cancel_preset_request_command(self, - endpoint: int = None, - expected_status: Status = Status.Success): + async def send_edit_atomic_request_rollback_command(self, + endpoint: int = None, + expected_status: Status = Status.Success): try: - await self.send_single_cmd(cmd=cluster.Commands.CancelPresetsSchedulesEditRequest(), + await self.send_single_cmd(cmd=cluster.Commands.AtomicRequest(requestType=2, + attributeRequests=[cluster.Attributes.Presets.attribute_id, cluster.Attributes.Schedules.attribute_id]), endpoint=endpoint) asserts.assert_equal(expected_status, Status.Success) except InteractionModelError as e: @@ -116,11 +131,11 @@ def steps_TC_TSTAT_4_2(self) -> list[TestStep]: steps = [ TestStep("1", "Commissioning, already done", is_commissioning=True), - TestStep("2", "TH writes to the Presets attribute without calling the StartPresetsSchedulesEditRequest command", - " Verify that the write request returns INVALID_IN_STATE error since the client didn't send a request to edit the presets by calling StartPresetsSchedulesEditRequest command."), - TestStep("3", "TH writes to the Presets attribute after calling the StartPresetsSchedulesEditRequest command but doesn't call CommitPresetsSchedulesRequest to commit", + TestStep("2", "TH writes to the Presets attribute without calling the AtomicRequest command", + " Verify that the write request returns INVALID_IN_STATE error since the client didn't send a request to edit the presets by calling AtomicRequest command."), + TestStep("3", "TH writes to the Presets attribute after calling the AtomicRequest command but doesn't call CommitPresetsSchedulesRequest to commit", "Verify that the Presets attribute was not updated since CommitPresetsSchedulesRequest command was not called."), - TestStep("4", "TH writes to the Presets attribute after calling the StartPresetsSchedulesEditRequest command and calls CommitPresetsSchedulesRequest to commit", + TestStep("4", "TH writes to the Presets attribute after calling the AtomicRequest command and calls CommitPresetsSchedulesRequest to commit", "Verify that the Presets attribute was updated with new presets."), TestStep("5", "TH writes to the Presets attribute with a built-in preset removed", "Verify that the CommitPresetsSchedulesRequest returned UNSUPPORTED_ACCESS (0x7e)."), @@ -157,49 +172,55 @@ async def test_TC_TSTAT_4_2(self): logger.info(f"Rx'd Presets: {presets}") asserts.assert_equal(presets, initial_presets, "Presets do not match initial value") - # Write to the presets attribute without calling StartPresetsSchedulesEditRequest command + # Write to the presets attribute without calling AtomicRequest command status = await self.write_presets(endpoint=endpoint, presets=new_presets) status_ok = (status == Status.InvalidInState) asserts.assert_true(status_ok, "Presets write did not return InvalidInState as expected") self.step("3") - if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.C07.Rsp")): - await self.send_edit_preset_request_command() + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.CFE.Rsp")): + await self.send_edit_atomic_request_begin_command() - # Write to the presets attribute after calling StartPresetsSchedulesEditRequest command + # Write to the presets attribute after calling AtomicRequest command status = await self.write_presets(endpoint=endpoint, presets=new_presets) status_ok = (status == Status.Success) asserts.assert_true(status_ok, "Presets write did not return Success as expected") - # Read the presets attribute and verify it was not updated since CommitPresetsSchedulesRequest was not called after writing presets + # Read the presets attribute and verify it was updated by the write presets = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=cluster.Attributes.Presets) logger.info(f"Rx'd Presets: {presets}") + asserts.assert_equal(presets, new_presets_with_handle, "Presets were updated, as expected") + + await self.send_edit_atomic_request_rollback_command() + + # Read the presets attribute and verify it has been properly rolled back + presets = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=cluster.Attributes.Presets) asserts.assert_equal(presets, initial_presets, "Presets were updated which is not expected") self.step("4") - if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.C07.Rsp") and self.check_pics("TSTAT.S.C09.Rsp")): + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.CFE.Rsp")): - # Send the StartPresetsSchedulesEditRequest command - await self.send_edit_preset_request_command() + # Send the AtomicRequest begin command + await self.send_edit_atomic_request_begin_command() - # Write to the presets attribute after calling StartPresetsSchedulesEditRequest command + # Write to the presets attribute after calling AtomicRequest command status = await self.write_presets(endpoint=endpoint, presets=new_presets) status_ok = (status == Status.Success) asserts.assert_true(status_ok, "Presets write did not return Success as expected") - # Send the CommitPresetsSchedulesRequest command - await self.send_commit_preset_request_command() + # Send the AtomicRequest commit command + await self.send_edit_atomic_request_commit_command() - # Read the presets attribute and verify it was updated since CommitPresetsSchedulesRequest was called after writing presets + # Read the presets attribute and verify it was updated since AtomicRequest commit was called after writing presets presets = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=cluster.Attributes.Presets) logger.info(f"Rx'd Presets: {presets}") asserts.assert_equal(presets, new_presets_with_handle, "Presets were not updated which is not expected") self.step("5") - if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.C07.Rsp") and self.check_pics("TSTAT.S.C09.Rsp")): + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.CFE.Rsp")): - # Send the StartPresetsSchedulesEditRequest command - await self.send_edit_preset_request_command() + # Send the AtomicRequest begin command + await self.send_edit_atomic_request_begin_command() # Write to the presets attribute after removing a built in preset from the list. Remove the first entry. test_presets = new_presets_with_handle.copy() @@ -208,11 +229,11 @@ async def test_TC_TSTAT_4_2(self): status_ok = (status == Status.Success) asserts.assert_true(status_ok, "Presets write did not return Success as expected") - # Send the CommitPresetsSchedulesRequest command and expect UnsupportedAccess - await self.send_commit_preset_request_command(expected_status=Status.UnsupportedAccess) + # Send the AtomicRequest commit command and expect ConstraintError for presets. + await self.send_edit_atomic_request_commit_command(expected_overall_status=Status.Failure, expected_preset_status=Status.ConstraintError) self.step("6") - if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.C06.Rsp") and self.check_pics("TSTAT.S.C07.Rsp") and self.check_pics("TSTAT.S.C09.Rsp")): + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.C06.Rsp") and self.check_pics("TSTAT.S.CFE.Rsp")): # Send the SetActivePresetRequest command await self.send_set_active_preset_handle_request_command(value=b'\x03') @@ -222,8 +243,8 @@ async def test_TC_TSTAT_4_2(self): logger.info(f"Rx'd ActivePresetHandle: {activePresetHandle}") asserts.assert_equal(activePresetHandle, b'\x03', "Active preset handle was not updated as expected") - # Send the StartPresetsSchedulesEditRequest command - await self.send_edit_preset_request_command() + # Send the AtomicRequest begin command + await self.send_edit_atomic_request_begin_command() # Write to the presets attribute after removing the preset that was set as the active preset handle. Remove the last entry with preset handle (b'\x03') test_presets = new_presets_with_handle.copy() @@ -232,31 +253,31 @@ async def test_TC_TSTAT_4_2(self): status_ok = (status == Status.Success) asserts.assert_true(status_ok, "Presets write did not return Success as expected") - # Send the CommitPresetsSchedulesRequest command and expect InvalidInState - await self.send_commit_preset_request_command(expected_status=Status.InvalidInState) + # Send the AtomicRequest commit command and expect InvalidInState for presets. + await self.send_edit_atomic_request_commit_command(expected_overall_status=Status.Failure, expected_preset_status=Status.InvalidInState) self.step("7") - if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.C07.Rsp") and self.check_pics("TSTAT.S.C09.Rsp")): + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.CFE.Rsp")): - # Send the StartPresetsSchedulesEditRequest command - await self.send_edit_preset_request_command() + # Send the AtomicRequest begin command + await self.send_edit_atomic_request_begin_command() # Write to the presets attribute after setting the builtIn flag to False for preset with handle (b'\x01') test_presets = copy.deepcopy(new_presets_with_handle) test_presets[0].builtIn = False status = await self.write_presets(endpoint=endpoint, presets=test_presets) - status_ok = (status == Status.Success) - asserts.assert_true(status_ok, "Presets write did not return Success as expected") + asserts.assert_equal(status, Status.ConstraintError, + "Presets write should return ConstraintError, because BuiltIn values do not match") - # Send the CommitPresetsSchedulesRequest command and expect UnsupportedAccess - await self.send_commit_preset_request_command(expected_status=Status.UnsupportedAccess) + # Clear state for next test. + await self.send_edit_atomic_request_rollback_command() self.step("8") - if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.C07.Rsp") and self.check_pics("TSTAT.S.C09.Rsp")): + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.CFE.Rsp")): - # Send the StartPresetsSchedulesEditRequest command - await self.send_edit_preset_request_command() + # Send the AtomicRequest begin command + await self.send_edit_atomic_request_begin_command() # Write to the presets attribute after adding a preset with builtIn set to True test_presets = copy.deepcopy(new_presets_with_handle) @@ -265,16 +286,17 @@ async def test_TC_TSTAT_4_2(self): status = await self.write_presets(endpoint=endpoint, presets=test_presets) status_ok = (status == Status.Success) - asserts.assert_true(status_ok, "Presets write did not return Success as expected") + asserts.assert_equal(status, Status.ConstraintError, + "Presets write should return ConstraintError, since we are trying to add a new built-in preset") - # Send the CommitPresetsSchedulesRequest command and expect ConstraintError - await self.send_commit_preset_request_command(expected_status=Status.ConstraintError) + # Clear state for next test. + await self.send_edit_atomic_request_rollback_command() self.step("9") - if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.C07.Rsp") and self.check_pics("TSTAT.S.C09.Rsp")): + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.CFE.Rsp")): - # Send the StartPresetsSchedulesEditRequest command - await self.send_edit_preset_request_command() + # Send the AtomicRequest begin command + await self.send_edit_atomic_request_begin_command() # Write to the presets attribute after adding a preset with a preset handle that doesn't exist in Presets attribute test_presets = copy.deepcopy(new_presets_with_handle) @@ -282,17 +304,17 @@ async def test_TC_TSTAT_4_2(self): name="Wake", coolingSetpoint=2800, heatingSetpoint=1800, builtIn=True)) status = await self.write_presets(endpoint=endpoint, presets=test_presets) - status_ok = (status == Status.Success) - asserts.assert_true(status_ok, "Presets write did not return Success as expected") + asserts.assert_equal(status, Status.NotFound, + "Presets write should return NotFound, since we are trying to modify non-existent preset") - # Send the CommitPresetsSchedulesRequest command and expect NotFound - await self.send_commit_preset_request_command(expected_status=Status.NotFound) + # Clear state for next test. + await self.send_edit_atomic_request_rollback_command() self.step("10") - if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.C07.Rsp") and self.check_pics("TSTAT.S.C09.Rsp")): + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.CFE.Rsp")): - # Send the StartPresetsSchedulesEditRequest command - await self.send_edit_preset_request_command() + # Send the AtomicRequest begin command + await self.send_edit_atomic_request_begin_command() # Write to the presets attribute after adding a duplicate preset with handle (b'\x03') test_presets = copy.deepcopy(new_presets_with_handle) @@ -300,66 +322,66 @@ async def test_TC_TSTAT_4_2(self): presetHandle=b'\x03', presetScenario=cluster.Enums.PresetScenarioEnum.kSleep, name="Sleep", coolingSetpoint=2700, heatingSetpoint=1900, builtIn=False)) status = await self.write_presets(endpoint=endpoint, presets=test_presets) - status_ok = (status == Status.Success) - asserts.assert_true(status_ok, "Presets write did not return Success as expected") + asserts.assert_equal(status, Status.ConstraintError, + "Presets write should return ConstraintError, since we have duplicated presets") - # Send the CommitPresetsSchedulesRequest command and expect ConstraintError - await self.send_commit_preset_request_command(expected_status=Status.ConstraintError) + # Clear state for next test. + await self.send_edit_atomic_request_rollback_command() self.step("11") - if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.C07.Rsp") and self.check_pics("TSTAT.S.C09.Rsp")): + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.CFE.Rsp")): - # Send the StartPresetsSchedulesEditRequest command - await self.send_edit_preset_request_command() + # Send the AtomicRequest begin command + await self.send_edit_atomic_request_begin_command() # Write to the presets attribute after setting the builtIn flag to True for preset with handle (b'\x03') test_presets = copy.deepcopy(new_presets_with_handle) test_presets[2].builtIn = True status = await self.write_presets(endpoint=endpoint, presets=test_presets) - status_ok = (status == Status.Success) - asserts.assert_true(status_ok, "Presets write did not return Success as expected") + asserts.assert_equal(status, Status.ConstraintError, + "Presets write should return ConstraintError, since we are trying to change whether a preset is BuiltIn") - # Send the CommitPresetsSchedulesRequest command and expect UnsupportedAccess - await self.send_commit_preset_request_command(expected_status=Status.UnsupportedAccess) + # Clear state for next test. + await self.send_edit_atomic_request_rollback_command() self.step("12") - if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.C07.Rsp") and self.check_pics("TSTAT.S.C09.Rsp")): + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.CFE.Rsp")): - # Send the StartPresetsSchedulesEditRequest command - await self.send_edit_preset_request_command() + # Send the AtomicRequest begin command + await self.send_edit_atomic_request_begin_command() # Write to the presets attribute after setting a name for preset with handle (b'\x01') that doesn't support names test_presets = copy.deepcopy(new_presets_with_handle) test_presets[0].name = "Occupied" status = await self.write_presets(endpoint=endpoint, presets=test_presets) - status_ok = (status == Status.Success) - asserts.assert_true(status_ok, "Presets write did not return Success as expected") + asserts.assert_equal(status, Status.ConstraintError, + "Presets write should return ConstraintError, since we are trying to set a name for a preset that does not support that") - # Send the CommitPresetsSchedulesRequest command and expect ConstraintError - await self.send_commit_preset_request_command(expected_status=Status.ConstraintError) + # Clear state for next test. + await self.send_edit_atomic_request_rollback_command() self.step("13") - if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.C07.Rsp") and self.check_pics("TSTAT.S.C09.Rsp")): + if self.pics_guard(self.check_pics("TSTAT.S.F08") and self.check_pics("TSTAT.S.A0050") and self.check_pics("TSTAT.S.CFE.Rsp")): - # Send the StartPresetsSchedulesEditRequest command - await self.send_edit_preset_request_command() + # Send the AtomicRequest begin command + await self.send_edit_atomic_request_begin_command() # Write to the presets attribute with a new valid preset added test_presets = copy.deepcopy(new_presets_with_handle) - test_presets.append(cluster.Structs.PresetStruct(presetHandle=b'\x04', presetScenario=cluster.Enums.PresetScenarioEnum.kWake, + test_presets.append(cluster.Structs.PresetStruct(presetHandle=NullValue, presetScenario=cluster.Enums.PresetScenarioEnum.kWake, name="Wake", coolingSetpoint=2800, heatingSetpoint=1800, builtIn=False)) status = await self.write_presets(endpoint=endpoint, presets=test_presets) status_ok = (status == Status.Success) - asserts.assert_true(status_ok, "Presets write did not return Success as expected") + asserts.assert_equal(status, Status.Success, "Presets write did not return Success as expected") - # Send the CancelPresetsSchedulesRequest command - await self.send_cancel_preset_request_command() + # Roll back + await self.send_edit_atomic_request_rollback_command() - # Send the CommitPresetsSchedulesRequest command and expect InvalidInState as the previous edit request was cancelled - await self.send_commit_preset_request_command(expected_status=Status.InvalidInState) + # Send the AtomicRequest commit command and expect InvalidInState as the previous edit request was cancelled + await self.send_edit_atomic_request_commit_command(expected_status=Status.InvalidInState) # TODO: Add tests for the total number of Presets exceeds the NumberOfPresets supported. Also Add tests for adding presets with preset scenario not present in PresetTypes. diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp index aaabdae8055e4b..ae2b7e12f93874 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.cpp @@ -22760,9 +22760,10 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, const chip::a namespace Occupancy { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint8_t * value) +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, + chip::BitMask * value) { - using Traits = NumericAttributeTraits; + using Traits = NumericAttributeTraits>; Traits::StorageType temp; uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); Protocols::InteractionModel::Status status = @@ -22776,9 +22777,10 @@ Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint8_t * val return status; } -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value, MarkAttributeDirty markDirty) +Protocols::InteractionModel::Status +Set(chip::EndpointId endpoint, chip::BitMask value, MarkAttributeDirty markDirty) { - using Traits = NumericAttributeTraits; + using Traits = NumericAttributeTraits>; if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) { return Protocols::InteractionModel::Status::ConstraintError; @@ -22789,9 +22791,10 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_BITMAP8_ATTRIBUTE_TYPE, markDirty); } -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value) +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, + chip::BitMask value) { - using Traits = NumericAttributeTraits; + using Traits = NumericAttributeTraits>; if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) { return Protocols::InteractionModel::Status::ConstraintError; @@ -23082,9 +23085,10 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value namespace HVACSystemTypeConfiguration { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint8_t * value) +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, + chip::BitMask * value) { - using Traits = NumericAttributeTraits; + using Traits = NumericAttributeTraits>; Traits::StorageType temp; uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); Protocols::InteractionModel::Status status = @@ -23098,9 +23102,11 @@ Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint8_t * val return status; } -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value, MarkAttributeDirty markDirty) +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, + chip::BitMask value, + MarkAttributeDirty markDirty) { - using Traits = NumericAttributeTraits; + using Traits = NumericAttributeTraits>; if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) { return Protocols::InteractionModel::Status::ConstraintError; @@ -23111,9 +23117,10 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_BITMAP8_ATTRIBUTE_TYPE, markDirty); } -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value) +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, + chip::BitMask value) { - using Traits = NumericAttributeTraits; + using Traits = NumericAttributeTraits>; if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) { return Protocols::InteractionModel::Status::ConstraintError; @@ -23200,7 +23207,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE, markDirty); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE, markDirty); } Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value) @@ -23213,7 +23220,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE); } } // namespace OccupiedCoolingSetpoint @@ -23246,7 +23253,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE, markDirty); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE, markDirty); } Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value) @@ -23259,7 +23266,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE); } } // namespace OccupiedHeatingSetpoint @@ -23292,7 +23299,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE, markDirty); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE, markDirty); } Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value) @@ -23305,7 +23312,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE); } } // namespace UnoccupiedCoolingSetpoint @@ -23338,7 +23345,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE, markDirty); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE, markDirty); } Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value) @@ -23351,7 +23358,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE); } } // namespace UnoccupiedHeatingSetpoint @@ -23384,7 +23391,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE, markDirty); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE, markDirty); } Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value) @@ -23397,7 +23404,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE); } } // namespace MinHeatSetpointLimit @@ -23430,7 +23437,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE, markDirty); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE, markDirty); } Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value) @@ -23443,7 +23450,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE); } } // namespace MaxHeatSetpointLimit @@ -23476,7 +23483,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE, markDirty); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE, markDirty); } Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value) @@ -23489,7 +23496,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE); } } // namespace MinCoolSetpointLimit @@ -23522,7 +23529,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE, markDirty); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE, markDirty); } Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value) @@ -23535,7 +23542,7 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value Traits::StorageType storageValue; Traits::WorkingToStorage(value, storageValue); uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_INT16S_ATTRIBUTE_TYPE); + return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_TEMPERATURE_ATTRIBUTE_TYPE); } } // namespace MaxCoolSetpointLimit @@ -25730,52 +25737,6 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, const chip::a } // namespace ActiveScheduleHandle -namespace PresetsSchedulesEditable { - -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, bool * value) -{ - using Traits = NumericAttributeTraits; - Traits::StorageType temp; - uint8_t * readable = Traits::ToAttributeStoreRepresentation(temp); - Protocols::InteractionModel::Status status = - emberAfReadAttribute(endpoint, Clusters::Thermostat::Id, Id, readable, sizeof(temp)); - VerifyOrReturnError(Protocols::InteractionModel::Status::Success == status, status); - if (!Traits::CanRepresentValue(/* isNullable = */ false, temp)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - *value = Traits::StorageToWorking(temp); - return status; -} - -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, bool value, MarkAttributeDirty markDirty) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_BOOLEAN_ATTRIBUTE_TYPE, markDirty); -} - -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, bool value) -{ - using Traits = NumericAttributeTraits; - if (!Traits::CanRepresentValue(/* isNullable = */ false, value)) - { - return Protocols::InteractionModel::Status::ConstraintError; - } - Traits::StorageType storageValue; - Traits::WorkingToStorage(value, storageValue); - uint8_t * writable = Traits::ToAttributeStoreRepresentation(storageValue); - return emberAfWriteAttribute(endpoint, Clusters::Thermostat::Id, Id, writable, ZCL_BOOLEAN_ATTRIBUTE_TYPE); -} - -} // namespace PresetsSchedulesEditable - namespace SetpointHoldExpiryTimestamp { Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, DataModel::Nullable & value) diff --git a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h index 85a8aabd8791cc..f49b495c4e5e47 100644 --- a/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h +++ b/zzz_generated/app-common/app-common/zap-generated/attributes/Accessors.h @@ -3607,9 +3607,12 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, const chip::a } // namespace OutdoorTemperature namespace Occupancy { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint8_t * value); // bitmap8 -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value); -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value, MarkAttributeDirty markDirty); +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, + chip::BitMask * value); // OccupancyBitmap +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, + chip::BitMask value); +Protocols::InteractionModel::Status +Set(chip::EndpointId endpoint, chip::BitMask value, MarkAttributeDirty markDirty); } // namespace Occupancy namespace AbsMinHeatSetpointLimit { @@ -3649,9 +3652,14 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value } // namespace PIHeatingDemand namespace HVACSystemTypeConfiguration { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, uint8_t * value); // bitmap8 -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value); -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint8_t value, MarkAttributeDirty markDirty); +Protocols::InteractionModel::Status +Get(chip::EndpointId endpoint, + chip::BitMask * value); // HVACSystemTypeBitmap +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, + chip::BitMask value); +Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, + chip::BitMask value, + MarkAttributeDirty markDirty); } // namespace HVACSystemTypeConfiguration namespace LocalTemperatureCalibration { @@ -3661,49 +3669,49 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int8_t value, } // namespace LocalTemperatureCalibration namespace OccupiedCoolingSetpoint { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // int16s +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // temperature Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value); Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value, MarkAttributeDirty markDirty); } // namespace OccupiedCoolingSetpoint namespace OccupiedHeatingSetpoint { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // int16s +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // temperature Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value); Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value, MarkAttributeDirty markDirty); } // namespace OccupiedHeatingSetpoint namespace UnoccupiedCoolingSetpoint { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // int16s +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // temperature Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value); Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value, MarkAttributeDirty markDirty); } // namespace UnoccupiedCoolingSetpoint namespace UnoccupiedHeatingSetpoint { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // int16s +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // temperature Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value); Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value, MarkAttributeDirty markDirty); } // namespace UnoccupiedHeatingSetpoint namespace MinHeatSetpointLimit { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // int16s +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // temperature Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value); Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value, MarkAttributeDirty markDirty); } // namespace MinHeatSetpointLimit namespace MaxHeatSetpointLimit { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // int16s +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // temperature Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value); Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value, MarkAttributeDirty markDirty); } // namespace MaxHeatSetpointLimit namespace MinCoolSetpointLimit { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // int16s +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // temperature Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value); Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value, MarkAttributeDirty markDirty); } // namespace MinCoolSetpointLimit namespace MaxCoolSetpointLimit { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // int16s +Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, int16_t * value); // temperature Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value); Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, int16_t value, MarkAttributeDirty markDirty); } // namespace MaxCoolSetpointLimit @@ -4029,12 +4037,6 @@ Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, const chip::a MarkAttributeDirty markDirty); } // namespace ActiveScheduleHandle -namespace PresetsSchedulesEditable { -Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, bool * value); // boolean -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, bool value); -Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, bool value, MarkAttributeDirty markDirty); -} // namespace PresetsSchedulesEditable - namespace SetpointHoldExpiryTimestamp { Protocols::InteractionModel::Status Get(chip::EndpointId endpoint, DataModel::Nullable & value); // epoch_s Protocols::InteractionModel::Status Set(chip::EndpointId endpoint, uint32_t value); diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index d1f11db1e93cc5..724e7a7eb88857 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -6331,23 +6331,11 @@ bool emberAfThermostatClusterSetActivePresetRequestCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::Thermostat::Commands::SetActivePresetRequest::DecodableType & commandData); /** - * @brief Thermostat Cluster StartPresetsSchedulesEditRequest Command callback (from client) + * @brief Thermostat Cluster AtomicRequest Command callback (from client) */ -bool emberAfThermostatClusterStartPresetsSchedulesEditRequestCallback( +bool emberAfThermostatClusterAtomicRequestCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Thermostat::Commands::StartPresetsSchedulesEditRequest::DecodableType & commandData); -/** - * @brief Thermostat Cluster CancelPresetsSchedulesEditRequest Command callback (from client) - */ -bool emberAfThermostatClusterCancelPresetsSchedulesEditRequestCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Thermostat::Commands::CancelPresetsSchedulesEditRequest::DecodableType & commandData); -/** - * @brief Thermostat Cluster CommitPresetsSchedulesRequest Command callback (from client) - */ -bool emberAfThermostatClusterCommitPresetsSchedulesRequestCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Thermostat::Commands::CommitPresetsSchedulesRequest::DecodableType & commandData); + const chip::app::Clusters::Thermostat::Commands::AtomicRequest::DecodableType & commandData); /** * @brief Fan Control Cluster Step Command callback (from client) */ diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h index 811352a6d38f7e..c32cf146b0da8b 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h @@ -130,6 +130,20 @@ static auto __attribute__((unused)) EnsureKnownEnumValue(Globals::AreaTypeTag va } } +static auto __attribute__((unused)) EnsureKnownEnumValue(Globals::AtomicRequestTypeEnum val) +{ + using EnumType = Globals::AtomicRequestTypeEnum; + switch (val) + { + case EnumType::kBeginWrite: + case EnumType::kCommitWrite: + case EnumType::kRollbackWrite: + return val; + default: + return EnumType::kUnknownEnumValue; + } +} + static auto __attribute__((unused)) EnsureKnownEnumValue(detail::ChangeIndicationEnum val) { using EnumType = detail::ChangeIndicationEnum; @@ -2716,7 +2730,6 @@ static auto __attribute__((unused)) EnsureKnownEnumValue(Thermostat::PresetScena using EnumType = Thermostat::PresetScenarioEnum; switch (val) { - case EnumType::kUnspecified: case EnumType::kOccupied: case EnumType::kUnoccupied: case EnumType::kSleep: diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h index 3c8d52d0bed54d..a66b926a9cacc6 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h @@ -279,6 +279,19 @@ enum class AreaTypeTag : uint8_t kUnknownEnumValue = 95, }; +// Enum for AtomicRequestTypeEnum +enum class AtomicRequestTypeEnum : uint8_t +{ + kBeginWrite = 0x00, + kCommitWrite = 0x01, + kRollbackWrite = 0x02, + // All received enum values that are not listed above will be mapped + // to kUnknownEnumValue. This is a helper enum value that should only + // be used by code to process how it handles receiving and unknown + // enum value. This specific should never be transmitted. + kUnknownEnumValue = 3, +}; + // Enum for FloorSurfaceTag enum class FloorSurfaceTag : uint8_t { @@ -3992,7 +4005,6 @@ enum class ControlSequenceOfOperationEnum : uint8_t // Enum for PresetScenarioEnum enum class PresetScenarioEnum : uint8_t { - kUnspecified = 0x00, kOccupied = 0x01, kUnoccupied = 0x02, kSleep = 0x03, @@ -4004,7 +4016,7 @@ enum class PresetScenarioEnum : uint8_t // to kUnknownEnumValue. This is a helper enum value that should only // be used by code to process how it handles receiving and unknown // enum value. This specific should never be transmitted. - kUnknownEnumValue = 7, + kUnknownEnumValue = 0, }; // Enum for SetpointChangeSourceEnum @@ -4116,7 +4128,6 @@ enum class Feature : uint32_t kLocalTemperatureNotExposed = 0x40, kMatterScheduleConfiguration = 0x80, kPresets = 0x100, - kSetpoints = 0x200, }; // Bitmap for HVACSystemTypeBitmap @@ -4128,6 +4139,12 @@ enum class HVACSystemTypeBitmap : uint8_t kHeatingUsesFuel = 0x20, }; +// Bitmap for OccupancyBitmap +enum class OccupancyBitmap : uint8_t +{ + kOccupied = 0x1, +}; + // Bitmap for PresetTypeFeaturesBitmap enum class PresetTypeFeaturesBitmap : uint16_t { diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp index 916d5ed27457ab..bea7e010160be2 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp @@ -602,6 +602,47 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) } // namespace LocationDescriptorStruct +namespace AtomicAttributeStatusStruct { +CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const +{ + DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + encoder.Encode(to_underlying(Fields::kAttributeID), attributeID); + encoder.Encode(to_underlying(Fields::kStatusCode), statusCode); + return encoder.Finalize(); +} + +CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) +{ + detail::StructDecodeIterator __iterator(reader); + while (true) + { + auto __element = __iterator.Next(); + if (std::holds_alternative(__element)) + { + return std::get(__element); + } + + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kAttributeID)) + { + err = DataModel::Decode(reader, attributeID); + } + else if (__context_tag == to_underlying(Fields::kStatusCode)) + { + err = DataModel::Decode(reader, statusCode); + } + else + { + } + + ReturnErrorOnFailure(err); + } +} + +} // namespace AtomicAttributeStatusStruct + } // namespace Structs } // namespace Globals @@ -21703,11 +21744,13 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) } } } // namespace SetActivePresetRequest. -namespace StartPresetsSchedulesEditRequest { +namespace AtomicResponse { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; - encoder.Encode(to_underlying(Fields::kTimeoutSeconds), timeoutSeconds); + encoder.Encode(to_underlying(Fields::kStatusCode), statusCode); + encoder.Encode(to_underlying(Fields::kAttributeStatus), attributeStatus); + encoder.Encode(to_underlying(Fields::kTimeout), timeout); return encoder.Finalize(); } @@ -21725,9 +21768,17 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) CHIP_ERROR err = CHIP_NO_ERROR; const uint8_t __context_tag = std::get(__element); - if (__context_tag == to_underlying(Fields::kTimeoutSeconds)) + if (__context_tag == to_underlying(Fields::kStatusCode)) + { + err = DataModel::Decode(reader, statusCode); + } + else if (__context_tag == to_underlying(Fields::kAttributeStatus)) { - err = DataModel::Decode(reader, timeoutSeconds); + err = DataModel::Decode(reader, attributeStatus); + } + else if (__context_tag == to_underlying(Fields::kTimeout)) + { + err = DataModel::Decode(reader, timeout); } else { @@ -21736,11 +21787,14 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) ReturnErrorOnFailure(err); } } -} // namespace StartPresetsSchedulesEditRequest. -namespace CancelPresetsSchedulesEditRequest { +} // namespace AtomicResponse. +namespace AtomicRequest { CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const { DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; + encoder.Encode(to_underlying(Fields::kRequestType), requestType); + encoder.Encode(to_underlying(Fields::kAttributeRequests), attributeRequests); + encoder.Encode(to_underlying(Fields::kTimeout), timeout); return encoder.Finalize(); } @@ -21754,29 +21808,30 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) { return std::get(__element); } - } -} -} // namespace CancelPresetsSchedulesEditRequest. -namespace CommitPresetsSchedulesRequest { -CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const -{ - DataModel::WrappedStructEncoder encoder{ aWriter, aTag }; - return encoder.Finalize(); -} -CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) -{ - detail::StructDecodeIterator __iterator(reader); - while (true) - { - auto __element = __iterator.Next(); - if (std::holds_alternative(__element)) + CHIP_ERROR err = CHIP_NO_ERROR; + const uint8_t __context_tag = std::get(__element); + + if (__context_tag == to_underlying(Fields::kRequestType)) { - return std::get(__element); + err = DataModel::Decode(reader, requestType); } + else if (__context_tag == to_underlying(Fields::kAttributeRequests)) + { + err = DataModel::Decode(reader, attributeRequests); + } + else if (__context_tag == to_underlying(Fields::kTimeout)) + { + err = DataModel::Decode(reader, timeout); + } + else + { + } + + ReturnErrorOnFailure(err); } } -} // namespace CommitPresetsSchedulesRequest. +} // namespace AtomicRequest. } // namespace Commands namespace Attributes { @@ -21902,8 +21957,6 @@ CHIP_ERROR TypeInfo::DecodableType::Decode(TLV::TLVReader & reader, const Concre return DataModel::Decode(reader, presets); case Attributes::Schedules::TypeInfo::GetAttributeId(): return DataModel::Decode(reader, schedules); - case Attributes::PresetsSchedulesEditable::TypeInfo::GetAttributeId(): - return DataModel::Decode(reader, presetsSchedulesEditable); case Attributes::SetpointHoldExpiryTimestamp::TypeInfo::GetAttributeId(): return DataModel::Decode(reader, setpointHoldExpiryTimestamp); case Attributes::GeneratedCommandList::TypeInfo::GetAttributeId(): diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index a32e7aed4a13de..f280ba39f8577c 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -350,6 +350,30 @@ using DecodableType = Type; } // namespace LocationDescriptorStruct +namespace AtomicAttributeStatusStruct { +enum class Fields : uint8_t +{ + kAttributeID = 0, + kStatusCode = 1, +}; + +struct Type +{ +public: + chip::AttributeId attributeID = static_cast(0); + uint8_t statusCode = static_cast(0); + + CHIP_ERROR Decode(TLV::TLVReader & reader); + + static constexpr bool kIsFabricScoped = false; + + CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; +}; + +using DecodableType = Type; + +} // namespace AtomicAttributeStatusStruct + } // namespace Structs namespace Attributes { @@ -29617,7 +29641,7 @@ struct Type Optional name; Optional presetHandle; DataModel::List transitions; - Optional> builtIn; + DataModel::Nullable builtIn; static constexpr bool kIsFabricScoped = false; @@ -29632,7 +29656,7 @@ struct DecodableType Optional name; Optional presetHandle; DataModel::DecodableList transitions; - Optional> builtIn; + DataModel::Nullable builtIn; CHIP_ERROR Decode(TLV::TLVReader & reader); @@ -29786,20 +29810,15 @@ struct Type; struct DecodableType; } // namespace SetActivePresetRequest -namespace StartPresetsSchedulesEditRequest { -struct Type; -struct DecodableType; -} // namespace StartPresetsSchedulesEditRequest - -namespace CancelPresetsSchedulesEditRequest { +namespace AtomicResponse { struct Type; struct DecodableType; -} // namespace CancelPresetsSchedulesEditRequest +} // namespace AtomicResponse -namespace CommitPresetsSchedulesRequest { +namespace AtomicRequest { struct Type; struct DecodableType; -} // namespace CommitPresetsSchedulesRequest +} // namespace AtomicRequest } // namespace Commands @@ -30048,20 +30067,24 @@ struct DecodableType CHIP_ERROR Decode(TLV::TLVReader & reader); }; }; // namespace SetActivePresetRequest -namespace StartPresetsSchedulesEditRequest { +namespace AtomicResponse { enum class Fields : uint8_t { - kTimeoutSeconds = 0, + kStatusCode = 0, + kAttributeStatus = 1, + kTimeout = 2, }; struct Type { public: // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand - static constexpr CommandId GetCommandId() { return Commands::StartPresetsSchedulesEditRequest::Id; } + static constexpr CommandId GetCommandId() { return Commands::AtomicResponse::Id; } static constexpr ClusterId GetClusterId() { return Clusters::Thermostat::Id; } - uint16_t timeoutSeconds = static_cast(0); + uint8_t statusCode = static_cast(0); + DataModel::List attributeStatus; + Optional timeout; CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; @@ -30073,56 +30096,37 @@ struct Type struct DecodableType { public: - static constexpr CommandId GetCommandId() { return Commands::StartPresetsSchedulesEditRequest::Id; } + static constexpr CommandId GetCommandId() { return Commands::AtomicResponse::Id; } static constexpr ClusterId GetClusterId() { return Clusters::Thermostat::Id; } - uint16_t timeoutSeconds = static_cast(0); + uint8_t statusCode = static_cast(0); + DataModel::DecodableList attributeStatus; + Optional timeout; CHIP_ERROR Decode(TLV::TLVReader & reader); }; -}; // namespace StartPresetsSchedulesEditRequest -namespace CancelPresetsSchedulesEditRequest { +}; // namespace AtomicResponse +namespace AtomicRequest { enum class Fields : uint8_t { + kRequestType = 0, + kAttributeRequests = 1, + kTimeout = 2, }; struct Type { public: // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand - static constexpr CommandId GetCommandId() { return Commands::CancelPresetsSchedulesEditRequest::Id; } + static constexpr CommandId GetCommandId() { return Commands::AtomicRequest::Id; } static constexpr ClusterId GetClusterId() { return Clusters::Thermostat::Id; } - CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; - - using ResponseType = DataModel::NullObjectType; - - static constexpr bool MustUseTimedInvoke() { return false; } -}; - -struct DecodableType -{ -public: - static constexpr CommandId GetCommandId() { return Commands::CancelPresetsSchedulesEditRequest::Id; } - static constexpr ClusterId GetClusterId() { return Clusters::Thermostat::Id; } - - CHIP_ERROR Decode(TLV::TLVReader & reader); -}; -}; // namespace CancelPresetsSchedulesEditRequest -namespace CommitPresetsSchedulesRequest { -enum class Fields : uint8_t -{ -}; - -struct Type -{ -public: - // Use GetCommandId instead of commandId directly to avoid naming conflict with CommandIdentification in ExecutionOfACommand - static constexpr CommandId GetCommandId() { return Commands::CommitPresetsSchedulesRequest::Id; } - static constexpr ClusterId GetClusterId() { return Clusters::Thermostat::Id; } + Globals::AtomicRequestTypeEnum requestType = static_cast(0); + DataModel::List attributeRequests; + Optional timeout; CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; - using ResponseType = DataModel::NullObjectType; + using ResponseType = Clusters::Thermostat::Commands::AtomicResponse::DecodableType; static constexpr bool MustUseTimedInvoke() { return false; } }; @@ -30130,12 +30134,15 @@ struct Type struct DecodableType { public: - static constexpr CommandId GetCommandId() { return Commands::CommitPresetsSchedulesRequest::Id; } + static constexpr CommandId GetCommandId() { return Commands::AtomicRequest::Id; } static constexpr ClusterId GetClusterId() { return Clusters::Thermostat::Id; } + Globals::AtomicRequestTypeEnum requestType = static_cast(0); + DataModel::DecodableList attributeRequests; + Optional timeout; CHIP_ERROR Decode(TLV::TLVReader & reader); }; -}; // namespace CommitPresetsSchedulesRequest +}; // namespace AtomicRequest } // namespace Commands namespace Attributes { @@ -30167,9 +30174,9 @@ struct TypeInfo namespace Occupancy { struct TypeInfo { - using Type = uint8_t; - using DecodableType = uint8_t; - using DecodableArgType = uint8_t; + using Type = chip::BitMask; + using DecodableType = chip::BitMask; + using DecodableArgType = chip::BitMask; static constexpr ClusterId GetClusterId() { return Clusters::Thermostat::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::Occupancy::Id; } @@ -30251,9 +30258,9 @@ struct TypeInfo namespace HVACSystemTypeConfiguration { struct TypeInfo { - using Type = uint8_t; - using DecodableType = uint8_t; - using DecodableArgType = uint8_t; + using Type = chip::BitMask; + using DecodableType = chip::BitMask; + using DecodableArgType = chip::BitMask; static constexpr ClusterId GetClusterId() { return Clusters::Thermostat::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::HVACSystemTypeConfiguration::Id; } @@ -30858,18 +30865,6 @@ struct TypeInfo static constexpr bool MustUseTimedWrite() { return false; } }; } // namespace Schedules -namespace PresetsSchedulesEditable { -struct TypeInfo -{ - using Type = bool; - using DecodableType = bool; - using DecodableArgType = bool; - - static constexpr ClusterId GetClusterId() { return Clusters::Thermostat::Id; } - static constexpr AttributeId GetAttributeId() { return Attributes::PresetsSchedulesEditable::Id; } - static constexpr bool MustUseTimedWrite() { return false; } -}; -} // namespace PresetsSchedulesEditable namespace SetpointHoldExpiryTimestamp { struct TypeInfo { @@ -30929,14 +30924,16 @@ struct TypeInfo Attributes::LocalTemperature::TypeInfo::DecodableType localTemperature; Attributes::OutdoorTemperature::TypeInfo::DecodableType outdoorTemperature; - Attributes::Occupancy::TypeInfo::DecodableType occupancy = static_cast(0); - Attributes::AbsMinHeatSetpointLimit::TypeInfo::DecodableType absMinHeatSetpointLimit = static_cast(0); - Attributes::AbsMaxHeatSetpointLimit::TypeInfo::DecodableType absMaxHeatSetpointLimit = static_cast(0); - Attributes::AbsMinCoolSetpointLimit::TypeInfo::DecodableType absMinCoolSetpointLimit = static_cast(0); - Attributes::AbsMaxCoolSetpointLimit::TypeInfo::DecodableType absMaxCoolSetpointLimit = static_cast(0); - Attributes::PICoolingDemand::TypeInfo::DecodableType PICoolingDemand = static_cast(0); - Attributes::PIHeatingDemand::TypeInfo::DecodableType PIHeatingDemand = static_cast(0); - Attributes::HVACSystemTypeConfiguration::TypeInfo::DecodableType HVACSystemTypeConfiguration = static_cast(0); + Attributes::Occupancy::TypeInfo::DecodableType occupancy = + static_cast>(0); + Attributes::AbsMinHeatSetpointLimit::TypeInfo::DecodableType absMinHeatSetpointLimit = static_cast(0); + Attributes::AbsMaxHeatSetpointLimit::TypeInfo::DecodableType absMaxHeatSetpointLimit = static_cast(0); + Attributes::AbsMinCoolSetpointLimit::TypeInfo::DecodableType absMinCoolSetpointLimit = static_cast(0); + Attributes::AbsMaxCoolSetpointLimit::TypeInfo::DecodableType absMaxCoolSetpointLimit = static_cast(0); + Attributes::PICoolingDemand::TypeInfo::DecodableType PICoolingDemand = static_cast(0); + Attributes::PIHeatingDemand::TypeInfo::DecodableType PIHeatingDemand = static_cast(0); + Attributes::HVACSystemTypeConfiguration::TypeInfo::DecodableType HVACSystemTypeConfiguration = + static_cast>(0); Attributes::LocalTemperatureCalibration::TypeInfo::DecodableType localTemperatureCalibration = static_cast(0); Attributes::OccupiedCoolingSetpoint::TypeInfo::DecodableType occupiedCoolingSetpoint = static_cast(0); Attributes::OccupiedHeatingSetpoint::TypeInfo::DecodableType occupiedHeatingSetpoint = static_cast(0); @@ -31000,7 +30997,6 @@ struct TypeInfo Attributes::ActiveScheduleHandle::TypeInfo::DecodableType activeScheduleHandle; Attributes::Presets::TypeInfo::DecodableType presets; Attributes::Schedules::TypeInfo::DecodableType schedules; - Attributes::PresetsSchedulesEditable::TypeInfo::DecodableType presetsSchedulesEditable = static_cast(0); Attributes::SetpointHoldExpiryTimestamp::TypeInfo::DecodableType setpointHoldExpiryTimestamp; Attributes::GeneratedCommandList::TypeInfo::DecodableType generatedCommandList; Attributes::AcceptedCommandList::TypeInfo::DecodableType acceptedCommandList; diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h index 7bd5d877f69897..b78c1e3410993a 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h @@ -5210,12 +5210,8 @@ namespace Schedules { static constexpr AttributeId Id = 0x00000051; } // namespace Schedules -namespace PresetsSchedulesEditable { -static constexpr AttributeId Id = 0x00000052; -} // namespace PresetsSchedulesEditable - namespace SetpointHoldExpiryTimestamp { -static constexpr AttributeId Id = 0x00000053; +static constexpr AttributeId Id = 0x00000052; } // namespace SetpointHoldExpiryTimestamp namespace GeneratedCommandList { diff --git a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h index e5948484cb568a..36ff7b0f098911 100644 --- a/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h +++ b/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h @@ -1348,17 +1348,13 @@ namespace SetActivePresetRequest { static constexpr CommandId Id = 0x00000006; } // namespace SetActivePresetRequest -namespace StartPresetsSchedulesEditRequest { -static constexpr CommandId Id = 0x00000007; -} // namespace StartPresetsSchedulesEditRequest - -namespace CancelPresetsSchedulesEditRequest { -static constexpr CommandId Id = 0x00000008; -} // namespace CancelPresetsSchedulesEditRequest +namespace AtomicResponse { +static constexpr CommandId Id = 0x000000FD; +} // namespace AtomicResponse -namespace CommitPresetsSchedulesRequest { -static constexpr CommandId Id = 0x00000009; -} // namespace CommitPresetsSchedulesRequest +namespace AtomicRequest { +static constexpr CommandId Id = 0x000000FE; +} // namespace AtomicRequest } // namespace Commands } // namespace Thermostat diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index 1fb3e0ccaab559..dd6fcb262adee4 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -9523,9 +9523,7 @@ class ServiceAreaSkipArea : public ClusterCommand | * ClearWeeklySchedule | 0x03 | | * SetActiveScheduleRequest | 0x05 | | * SetActivePresetRequest | 0x06 | -| * StartPresetsSchedulesEditRequest | 0x07 | -| * CancelPresetsSchedulesEditRequest | 0x08 | -| * CommitPresetsSchedulesRequest | 0x09 | +| * AtomicRequest | 0xFE | |------------------------------------------------------------------------------| | Attributes: | | | * LocalTemperature | 0x0000 | @@ -9587,8 +9585,7 @@ class ServiceAreaSkipArea : public ClusterCommand | * ActiveScheduleHandle | 0x004F | | * Presets | 0x0050 | | * Schedules | 0x0051 | -| * PresetsSchedulesEditable | 0x0052 | -| * SetpointHoldExpiryTimestamp | 0x0053 | +| * SetpointHoldExpiryTimestamp | 0x0052 | | * GeneratedCommandList | 0xFFF8 | | * AcceptedCommandList | 0xFFF9 | | * EventList | 0xFFFA | @@ -9835,96 +9832,24 @@ class ThermostatSetActivePresetRequest : public ClusterCommand }; /* - * Command StartPresetsSchedulesEditRequest + * Command AtomicRequest */ -class ThermostatStartPresetsSchedulesEditRequest : public ClusterCommand +class ThermostatAtomicRequest : public ClusterCommand { public: - ThermostatStartPresetsSchedulesEditRequest(CredentialIssuerCommands * credsIssuerConfig) : - ClusterCommand("start-presets-schedules-edit-request", credsIssuerConfig) - { - AddArgument("TimeoutSeconds", 0, UINT16_MAX, &mRequest.timeoutSeconds); - ClusterCommand::AddArguments(); - } - - CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override - { - constexpr chip::ClusterId clusterId = chip::app::Clusters::Thermostat::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::Thermostat::Commands::StartPresetsSchedulesEditRequest::Id; - - ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, - commandId, endpointIds.at(0)); - return ClusterCommand::SendCommand(device, endpointIds.at(0), clusterId, commandId, mRequest); - } - - CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override - { - constexpr chip::ClusterId clusterId = chip::app::Clusters::Thermostat::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::Thermostat::Commands::StartPresetsSchedulesEditRequest::Id; - - ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on Group %u", clusterId, commandId, - groupId); - - return ClusterCommand::SendGroupCommand(groupId, fabricIndex, clusterId, commandId, mRequest); - } - -private: - chip::app::Clusters::Thermostat::Commands::StartPresetsSchedulesEditRequest::Type mRequest; -}; - -/* - * Command CancelPresetsSchedulesEditRequest - */ -class ThermostatCancelPresetsSchedulesEditRequest : public ClusterCommand -{ -public: - ThermostatCancelPresetsSchedulesEditRequest(CredentialIssuerCommands * credsIssuerConfig) : - ClusterCommand("cancel-presets-schedules-edit-request", credsIssuerConfig) - { - ClusterCommand::AddArguments(); - } - - CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override - { - constexpr chip::ClusterId clusterId = chip::app::Clusters::Thermostat::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::Thermostat::Commands::CancelPresetsSchedulesEditRequest::Id; - - ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, - commandId, endpointIds.at(0)); - return ClusterCommand::SendCommand(device, endpointIds.at(0), clusterId, commandId, mRequest); - } - - CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override - { - constexpr chip::ClusterId clusterId = chip::app::Clusters::Thermostat::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::Thermostat::Commands::CancelPresetsSchedulesEditRequest::Id; - - ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on Group %u", clusterId, commandId, - groupId); - - return ClusterCommand::SendGroupCommand(groupId, fabricIndex, clusterId, commandId, mRequest); - } - -private: - chip::app::Clusters::Thermostat::Commands::CancelPresetsSchedulesEditRequest::Type mRequest; -}; - -/* - * Command CommitPresetsSchedulesRequest - */ -class ThermostatCommitPresetsSchedulesRequest : public ClusterCommand -{ -public: - ThermostatCommitPresetsSchedulesRequest(CredentialIssuerCommands * credsIssuerConfig) : - ClusterCommand("commit-presets-schedules-request", credsIssuerConfig) + ThermostatAtomicRequest(CredentialIssuerCommands * credsIssuerConfig) : + ClusterCommand("atomic-request", credsIssuerConfig), mComplex_AttributeRequests(&mRequest.attributeRequests) { + AddArgument("RequestType", 0, UINT8_MAX, &mRequest.requestType); + AddArgument("AttributeRequests", &mComplex_AttributeRequests); + AddArgument("Timeout", 0, UINT16_MAX, &mRequest.timeout); ClusterCommand::AddArguments(); } CHIP_ERROR SendCommand(chip::DeviceProxy * device, std::vector endpointIds) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::Thermostat::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::Thermostat::Commands::CommitPresetsSchedulesRequest::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::Thermostat::Commands::AtomicRequest::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointIds.at(0)); @@ -9934,7 +9859,7 @@ class ThermostatCommitPresetsSchedulesRequest : public ClusterCommand CHIP_ERROR SendGroupCommand(chip::GroupId groupId, chip::FabricIndex fabricIndex) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::Thermostat::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::Thermostat::Commands::CommitPresetsSchedulesRequest::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::Thermostat::Commands::AtomicRequest::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on Group %u", clusterId, commandId, groupId); @@ -9943,7 +9868,8 @@ class ThermostatCommitPresetsSchedulesRequest : public ClusterCommand } private: - chip::app::Clusters::Thermostat::Commands::CommitPresetsSchedulesRequest::Type mRequest; + chip::app::Clusters::Thermostat::Commands::AtomicRequest::Type mRequest; + TypedComplexArgument> mComplex_AttributeRequests; }; /*----------------------------------------------------------------------------*\ @@ -23119,16 +23045,14 @@ void registerClusterThermostat(Commands & commands, CredentialIssuerCommands * c // // Commands // - make_unique(Id, credsIssuerConfig), // - make_unique(credsIssuerConfig), // - make_unique(credsIssuerConfig), // - make_unique(credsIssuerConfig), // - make_unique(credsIssuerConfig), // - make_unique(credsIssuerConfig), // - make_unique(credsIssuerConfig), // - make_unique(credsIssuerConfig), // - make_unique(credsIssuerConfig), // - make_unique(credsIssuerConfig), // + make_unique(Id, credsIssuerConfig), // + make_unique(credsIssuerConfig), // + make_unique(credsIssuerConfig), // + make_unique(credsIssuerConfig), // + make_unique(credsIssuerConfig), // + make_unique(credsIssuerConfig), // + make_unique(credsIssuerConfig), // + make_unique(credsIssuerConfig), // // // Attributes // @@ -23208,8 +23132,6 @@ void registerClusterThermostat(Commands & commands, CredentialIssuerCommands * c make_unique(Id, "active-schedule-handle", Attributes::ActiveScheduleHandle::Id, credsIssuerConfig), // make_unique(Id, "presets", Attributes::Presets::Id, credsIssuerConfig), // make_unique(Id, "schedules", Attributes::Schedules::Id, credsIssuerConfig), // - make_unique(Id, "presets-schedules-editable", Attributes::PresetsSchedulesEditable::Id, - credsIssuerConfig), // make_unique(Id, "setpoint-hold-expiry-timestamp", Attributes::SetpointHoldExpiryTimestamp::Id, credsIssuerConfig), // make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // @@ -23225,8 +23147,8 @@ void registerClusterThermostat(Commands & commands, CredentialIssuerCommands * c make_unique>>(Id, "outdoor-temperature", INT16_MIN, INT16_MAX, Attributes::OutdoorTemperature::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>(Id, "occupancy", 0, UINT8_MAX, Attributes::Occupancy::Id, - WriteCommandType::kForceWrite, credsIssuerConfig), // + make_unique>>( + Id, "occupancy", 0, UINT8_MAX, Attributes::Occupancy::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>(Id, "abs-min-heat-setpoint-limit", INT16_MIN, INT16_MAX, Attributes::AbsMinHeatSetpointLimit::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // @@ -23243,9 +23165,9 @@ void registerClusterThermostat(Commands & commands, CredentialIssuerCommands * c WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>(Id, "piheating-demand", 0, UINT8_MAX, Attributes::PIHeatingDemand::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>(Id, "hvacsystem-type-configuration", 0, UINT8_MAX, - Attributes::HVACSystemTypeConfiguration::Id, WriteCommandType::kWrite, - credsIssuerConfig), // + make_unique>>( + Id, "hvacsystem-type-configuration", 0, UINT8_MAX, Attributes::HVACSystemTypeConfiguration::Id, + WriteCommandType::kWrite, credsIssuerConfig), // make_unique>(Id, "local-temperature-calibration", INT8_MIN, INT8_MAX, Attributes::LocalTemperatureCalibration::Id, WriteCommandType::kWrite, credsIssuerConfig), // @@ -23376,8 +23298,6 @@ void registerClusterThermostat(Commands & commands, CredentialIssuerCommands * c make_unique>>( Id, "schedules", Attributes::Schedules::Id, WriteCommandType::kWrite, credsIssuerConfig), // - make_unique>(Id, "presets-schedules-editable", 0, 1, Attributes::PresetsSchedulesEditable::Id, - WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>>(Id, "setpoint-hold-expiry-timestamp", 0, UINT32_MAX, Attributes::SetpointHoldExpiryTimestamp::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // @@ -23474,8 +23394,6 @@ void registerClusterThermostat(Commands & commands, CredentialIssuerCommands * c make_unique(Id, "active-schedule-handle", Attributes::ActiveScheduleHandle::Id, credsIssuerConfig), // make_unique(Id, "presets", Attributes::Presets::Id, credsIssuerConfig), // make_unique(Id, "schedules", Attributes::Schedules::Id, credsIssuerConfig), // - make_unique(Id, "presets-schedules-editable", Attributes::PresetsSchedulesEditable::Id, - credsIssuerConfig), // make_unique(Id, "setpoint-hold-expiry-timestamp", Attributes::SetpointHoldExpiryTimestamp::Id, credsIssuerConfig), // make_unique(Id, "generated-command-list", Attributes::GeneratedCommandList::Id, credsIssuerConfig), // diff --git a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp index 51a2d775b6e94c..b57db005357f57 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.cpp @@ -358,6 +358,38 @@ void ComplexArgumentParser::Finalize(chip::app::Clusters::detail::Structs::Appli ComplexArgumentParser::Finalize(request.applicationID); } +CHIP_ERROR ComplexArgumentParser::Setup(const char * label, + chip::app::Clusters::Globals::Structs::AtomicAttributeStatusStruct::Type & request, + Json::Value & value) +{ + VerifyOrReturnError(value.isObject(), CHIP_ERROR_INVALID_ARGUMENT); + + // Copy to track which members we already processed. + Json::Value valueCopy(value); + + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("AtomicAttributeStatusStruct.attributeID", "attributeID", + value.isMember("attributeID"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("AtomicAttributeStatusStruct.statusCode", "statusCode", + value.isMember("statusCode"))); + + char labelWithMember[kMaxLabelLength]; + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "attributeID"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.attributeID, value["attributeID"])); + valueCopy.removeMember("attributeID"); + + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "statusCode"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.statusCode, value["statusCode"])); + valueCopy.removeMember("statusCode"); + + return ComplexArgumentParser::EnsureNoMembersRemaining(label, valueCopy); +} + +void ComplexArgumentParser::Finalize(chip::app::Clusters::Globals::Structs::AtomicAttributeStatusStruct::Type & request) +{ + ComplexArgumentParser::Finalize(request.attributeID); + ComplexArgumentParser::Finalize(request.statusCode); +} + CHIP_ERROR ComplexArgumentParser::Setup(const char * label, chip::app::Clusters::detail::Structs::ErrorStateStruct::Type & request, Json::Value & value) { @@ -4178,6 +4210,7 @@ CHIP_ERROR ComplexArgumentParser::Setup(const char * label, ComplexArgumentParser::EnsureMemberExist("ScheduleStruct.systemMode", "systemMode", value.isMember("systemMode"))); ReturnErrorOnFailure( ComplexArgumentParser::EnsureMemberExist("ScheduleStruct.transitions", "transitions", value.isMember("transitions"))); + ReturnErrorOnFailure(ComplexArgumentParser::EnsureMemberExist("ScheduleStruct.builtIn", "builtIn", value.isMember("builtIn"))); char labelWithMember[kMaxLabelLength]; snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "scheduleHandle"); @@ -4206,11 +4239,8 @@ CHIP_ERROR ComplexArgumentParser::Setup(const char * label, ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.transitions, value["transitions"])); valueCopy.removeMember("transitions"); - if (value.isMember("builtIn")) - { - snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "builtIn"); - ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.builtIn, value["builtIn"])); - } + snprintf(labelWithMember, sizeof(labelWithMember), "%s.%s", label, "builtIn"); + ReturnErrorOnFailure(ComplexArgumentParser::Setup(labelWithMember, request.builtIn, value["builtIn"])); valueCopy.removeMember("builtIn"); return ComplexArgumentParser::EnsureNoMembersRemaining(label, valueCopy); diff --git a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.h b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.h index 14d10ae89ba82b..b08c731a32689d 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/ComplexArgumentParser.h @@ -62,6 +62,11 @@ static CHIP_ERROR Setup(const char * label, chip::app::Clusters::detail::Structs static void Finalize(chip::app::Clusters::detail::Structs::ApplicationStruct::Type & request); +static CHIP_ERROR Setup(const char * label, chip::app::Clusters::Globals::Structs::AtomicAttributeStatusStruct::Type & request, + Json::Value & value); + +static void Finalize(chip::app::Clusters::Globals::Structs::AtomicAttributeStatusStruct::Type & request); + static CHIP_ERROR Setup(const char * label, chip::app::Clusters::detail::Structs::ErrorStateStruct::Type & request, Json::Value & value); diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp index de22cae0e0346c..2e3b5bc55ddd6f 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp @@ -318,6 +318,32 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, return CHIP_NO_ERROR; } +CHIP_ERROR +DataModelLogger::LogValue(const char * label, size_t indent, + const chip::app::Clusters::Globals::Structs::AtomicAttributeStatusStruct::DecodableType & value) +{ + DataModelLogger::LogString(label, indent, "{"); + { + CHIP_ERROR err = LogValue("AttributeID", indent + 1, value.attributeID); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'AttributeID'"); + return err; + } + } + { + CHIP_ERROR err = LogValue("StatusCode", indent + 1, value.statusCode); + if (err != CHIP_NO_ERROR) + { + DataModelLogger::LogString(indent + 1, "Struct truncated due to invalid value for 'StatusCode'"); + return err; + } + } + DataModelLogger::LogString(indent, "}"); + + return CHIP_NO_ERROR; +} + CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, const chip::app::Clusters::detail::Structs::ErrorStateStruct::DecodableType & value) { @@ -8471,6 +8497,16 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, DataModelLogger::LogString(indent, "}"); return CHIP_NO_ERROR; } +CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, + const Thermostat::Commands::AtomicResponse::DecodableType & value) +{ + DataModelLogger::LogString(label, indent, "{"); + ReturnErrorOnFailure(DataModelLogger::LogValue("statusCode", indent + 1, value.statusCode)); + ReturnErrorOnFailure(DataModelLogger::LogValue("attributeStatus", indent + 1, value.attributeStatus)); + ReturnErrorOnFailure(DataModelLogger::LogValue("timeout", indent + 1, value.timeout)); + DataModelLogger::LogString(indent, "}"); + return CHIP_NO_ERROR; +} CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, const WiFiNetworkManagement::Commands::NetworkPassphraseResponse::DecodableType & value) { @@ -14929,7 +14965,7 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP return DataModelLogger::LogValue("OutdoorTemperature", 1, value); } case Thermostat::Attributes::Occupancy::Id: { - uint8_t value; + chip::BitMask value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("Occupancy", 1, value); } @@ -14964,7 +15000,7 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP return DataModelLogger::LogValue("PIHeatingDemand", 1, value); } case Thermostat::Attributes::HVACSystemTypeConfiguration::Id: { - uint8_t value; + chip::BitMask value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("HVACSystemTypeConfiguration", 1, value); } @@ -15213,11 +15249,6 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("Schedules", 1, value); } - case Thermostat::Attributes::PresetsSchedulesEditable::Id: { - bool value; - ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); - return DataModelLogger::LogValue("PresetsSchedulesEditable", 1, value); - } case Thermostat::Attributes::SetpointHoldExpiryTimestamp::Id: { chip::app::DataModel::Nullable value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); @@ -19796,6 +19827,11 @@ CHIP_ERROR DataModelLogger::LogCommand(const chip::app::ConcreteCommandPath & pa ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("GetWeeklyScheduleResponse", 1, value); } + case Thermostat::Commands::AtomicResponse::Id: { + Thermostat::Commands::AtomicResponse::DecodableType value; + ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); + return DataModelLogger::LogValue("AtomicResponse", 1, value); + } } break; } diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h index 7d7e961dcb16d3..fa3fc1a2760fc2 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.h @@ -44,6 +44,9 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::detail::Structs::ApplicationStruct::DecodableType & value); +static CHIP_ERROR LogValue(const char * label, size_t indent, + const chip::app::Clusters::Globals::Structs::AtomicAttributeStatusStruct::DecodableType & value); + static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::detail::Structs::ErrorStateStruct::DecodableType & value); @@ -798,6 +801,8 @@ static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::ServiceArea::Commands::SkipAreaResponse::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::Thermostat::Commands::GetWeeklyScheduleResponse::DecodableType & value); +static CHIP_ERROR LogValue(const char * label, size_t indent, + const chip::app::Clusters::Thermostat::Commands::AtomicResponse::DecodableType & value); static CHIP_ERROR LogValue(const char * label, size_t indent, const chip::app::Clusters::WiFiNetworkManagement::Commands::NetworkPassphraseResponse::DecodableType & value); diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index 0643c1f99d09e4..195bf8b2a5a5b8 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -107637,9 +107637,7 @@ class SubscribeAttributePumpConfigurationAndControlClusterRevision : public Subs | * ClearWeeklySchedule | 0x03 | | * SetActiveScheduleRequest | 0x05 | | * SetActivePresetRequest | 0x06 | -| * StartPresetsSchedulesEditRequest | 0x07 | -| * CancelPresetsSchedulesEditRequest | 0x08 | -| * CommitPresetsSchedulesRequest | 0x09 | +| * AtomicRequest | 0xFE | |------------------------------------------------------------------------------| | Attributes: | | | * LocalTemperature | 0x0000 | @@ -107701,8 +107699,7 @@ class SubscribeAttributePumpConfigurationAndControlClusterRevision : public Subs | * ActiveScheduleHandle | 0x004F | | * Presets | 0x0050 | | * Schedules | 0x0051 | -| * PresetsSchedulesEditable | 0x0052 | -| * SetpointHoldExpiryTimestamp | 0x0053 | +| * SetpointHoldExpiryTimestamp | 0x0052 | | * GeneratedCommandList | 0xFFF8 | | * AcceptedCommandList | 0xFFF9 | | * EventList | 0xFFFA | @@ -108043,15 +108040,22 @@ class ThermostatSetActivePresetRequest : public ClusterCommand { #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL /* - * Command StartPresetsSchedulesEditRequest + * Command AtomicRequest */ -class ThermostatStartPresetsSchedulesEditRequest : public ClusterCommand { +class ThermostatAtomicRequest : public ClusterCommand { public: - ThermostatStartPresetsSchedulesEditRequest() - : ClusterCommand("start-presets-schedules-edit-request") + ThermostatAtomicRequest() + : ClusterCommand("atomic-request") + , mComplex_AttributeRequests(&mRequest.attributeRequests) { #if MTR_ENABLE_PROVISIONAL - AddArgument("TimeoutSeconds", 0, UINT16_MAX, &mRequest.timeoutSeconds); + AddArgument("RequestType", 0, UINT8_MAX, &mRequest.requestType); +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + AddArgument("AttributeRequests", &mComplex_AttributeRequests); +#endif // MTR_ENABLE_PROVISIONAL +#if MTR_ENABLE_PROVISIONAL + AddArgument("Timeout", 0, UINT16_MAX, &mRequest.timeout); #endif // MTR_ENABLE_PROVISIONAL ClusterCommand::AddArguments(); } @@ -108059,130 +108063,63 @@ class ThermostatStartPresetsSchedulesEditRequest : public ClusterCommand { CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override { constexpr chip::ClusterId clusterId = chip::app::Clusters::Thermostat::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::Thermostat::Commands::StartPresetsSchedulesEditRequest::Id; + constexpr chip::CommandId commandId = chip::app::Clusters::Thermostat::Commands::AtomicRequest::Id; ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointId); dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); __auto_type * cluster = [[MTRBaseClusterThermostat alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - __auto_type * params = [[MTRThermostatClusterStartPresetsSchedulesEditRequestParams alloc] init]; + __auto_type * params = [[MTRThermostatClusterAtomicRequestParams alloc] init]; params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; #if MTR_ENABLE_PROVISIONAL - params.timeoutSeconds = [NSNumber numberWithUnsignedShort:mRequest.timeoutSeconds]; + params.requestType = [NSNumber numberWithUnsignedChar:chip::to_underlying(mRequest.requestType)]; #endif // MTR_ENABLE_PROVISIONAL - uint16_t repeatCount = mRepeatCount.ValueOr(1); - uint16_t __block responsesNeeded = repeatCount; - while (repeatCount--) { - [cluster startPresetsSchedulesEditRequestWithParams:params completion: - ^(NSError * _Nullable error) { - responsesNeeded--; - if (error != nil) { - mError = error; - LogNSError("Error", error); - RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(commandId), error); - } - if (responsesNeeded == 0) { - SetCommandExitStatus(mError); - } - }]; +#if MTR_ENABLE_PROVISIONAL + { // Scope for our temporary variables + auto * array_0 = [NSMutableArray new]; + for (auto & entry_0 : mRequest.attributeRequests) { + NSNumber * newElement_0; + newElement_0 = [NSNumber numberWithUnsignedInt:entry_0]; + [array_0 addObject:newElement_0]; + } + params.attributeRequests = array_0; } - return CHIP_NO_ERROR; - } - -private: - chip::app::Clusters::Thermostat::Commands::StartPresetsSchedulesEditRequest::Type mRequest; -}; - #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL -/* - * Command CancelPresetsSchedulesEditRequest - */ -class ThermostatCancelPresetsSchedulesEditRequest : public ClusterCommand { -public: - ThermostatCancelPresetsSchedulesEditRequest() - : ClusterCommand("cancel-presets-schedules-edit-request") - { - ClusterCommand::AddArguments(); - } - - CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override - { - constexpr chip::ClusterId clusterId = chip::app::Clusters::Thermostat::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::Thermostat::Commands::CancelPresetsSchedulesEditRequest::Id; - - ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointId); - - dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterThermostat alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - __auto_type * params = [[MTRThermostatClusterCancelPresetsSchedulesEditRequestParams alloc] init]; - params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; - uint16_t repeatCount = mRepeatCount.ValueOr(1); - uint16_t __block responsesNeeded = repeatCount; - while (repeatCount--) { - [cluster cancelPresetsSchedulesEditRequestWithParams:params completion: - ^(NSError * _Nullable error) { - responsesNeeded--; - if (error != nil) { - mError = error; - LogNSError("Error", error); - RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(commandId), error); - } - if (responsesNeeded == 0) { - SetCommandExitStatus(mError); - } - }]; + if (mRequest.timeout.HasValue()) { + params.timeout = [NSNumber numberWithUnsignedShort:mRequest.timeout.Value()]; + } else { + params.timeout = nil; } - return CHIP_NO_ERROR; - } - -private: -}; - #endif // MTR_ENABLE_PROVISIONAL -#if MTR_ENABLE_PROVISIONAL -/* - * Command CommitPresetsSchedulesRequest - */ -class ThermostatCommitPresetsSchedulesRequest : public ClusterCommand { -public: - ThermostatCommitPresetsSchedulesRequest() - : ClusterCommand("commit-presets-schedules-request") - { - ClusterCommand::AddArguments(); - } - - CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override - { - constexpr chip::ClusterId clusterId = chip::app::Clusters::Thermostat::Id; - constexpr chip::CommandId commandId = chip::app::Clusters::Thermostat::Commands::CommitPresetsSchedulesRequest::Id; - - ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") command (0x%08" PRIX32 ") on endpoint %u", clusterId, commandId, endpointId); - - dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterThermostat alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - __auto_type * params = [[MTRThermostatClusterCommitPresetsSchedulesRequestParams alloc] init]; - params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; uint16_t repeatCount = mRepeatCount.ValueOr(1); uint16_t __block responsesNeeded = repeatCount; while (repeatCount--) { - [cluster commitPresetsSchedulesRequestWithParams:params completion: - ^(NSError * _Nullable error) { - responsesNeeded--; - if (error != nil) { - mError = error; - LogNSError("Error", error); - RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(commandId), error); - } - if (responsesNeeded == 0) { - SetCommandExitStatus(mError); - } - }]; + [cluster atomicRequestWithParams:params completion: + ^(MTRThermostatClusterAtomicResponseParams * _Nullable values, NSError * _Nullable error) { + NSLog(@"Values: %@", values); + if (error == nil) { + constexpr chip::CommandId responseId = chip::app::Clusters::Thermostat::Commands::AtomicResponse::Id; + RemoteDataModelLogger::LogCommandAsJSON(@(endpointId), @(clusterId), @(responseId), values); + } + responsesNeeded--; + if (error != nil) { + mError = error; + LogNSError("Error", error); + constexpr chip::CommandId responseId = chip::app::Clusters::Thermostat::Commands::AtomicResponse::Id; + RemoteDataModelLogger::LogCommandErrorAsJSON(@(endpointId), @(clusterId), @(responseId), error); + } + if (responsesNeeded == 0) { + SetCommandExitStatus(mError); + } + }]; } return CHIP_NO_ERROR; } private: + chip::app::Clusters::Thermostat::Commands::AtomicRequest::Type mRequest; + TypedComplexArgument> mComplex_AttributeRequests; }; #endif // MTR_ENABLE_PROVISIONAL @@ -114286,14 +114223,10 @@ class WriteThermostatSchedules : public WriteAttribute { } newElement_0.transitions = array_2; } - if (entry_0.builtIn.HasValue()) { - if (entry_0.builtIn.Value().IsNull()) { - newElement_0.builtIn = nil; - } else { - newElement_0.builtIn = [NSNumber numberWithBool:entry_0.builtIn.Value().Value()]; - } - } else { + if (entry_0.builtIn.IsNull()) { newElement_0.builtIn = nil; + } else { + newElement_0.builtIn = [NSNumber numberWithBool:entry_0.builtIn.Value()]; } [array_0 addObject:newElement_0]; } @@ -114363,91 +114296,6 @@ class SubscribeAttributeThermostatSchedules : public SubscribeAttribute { #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL -/* - * Attribute PresetsSchedulesEditable - */ -class ReadThermostatPresetsSchedulesEditable : public ReadAttribute { -public: - ReadThermostatPresetsSchedulesEditable() - : ReadAttribute("presets-schedules-editable") - { - } - - ~ReadThermostatPresetsSchedulesEditable() - { - } - - CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override - { - constexpr chip::ClusterId clusterId = chip::app::Clusters::Thermostat::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::Thermostat::Attributes::PresetsSchedulesEditable::Id; - - ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReadAttribute (0x%08" PRIX32 ") on endpoint %u", endpointId, clusterId, attributeId); - - dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterThermostat alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - [cluster readAttributePresetsSchedulesEditableWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"Thermostat.PresetsSchedulesEditable response %@", [value description]); - if (error == nil) { - RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); - } else { - LogNSError("Thermostat PresetsSchedulesEditable read Error", error); - RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); - } - SetCommandExitStatus(error); - }]; - return CHIP_NO_ERROR; - } -}; - -class SubscribeAttributeThermostatPresetsSchedulesEditable : public SubscribeAttribute { -public: - SubscribeAttributeThermostatPresetsSchedulesEditable() - : SubscribeAttribute("presets-schedules-editable") - { - } - - ~SubscribeAttributeThermostatPresetsSchedulesEditable() - { - } - - CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override - { - constexpr chip::ClusterId clusterId = chip::app::Clusters::Thermostat::Id; - constexpr chip::CommandId attributeId = chip::app::Clusters::Thermostat::Attributes::PresetsSchedulesEditable::Id; - - ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") ReportAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); - dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterThermostat alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(mMinInterval) maxInterval:@(mMaxInterval)]; - if (mKeepSubscriptions.HasValue()) { - params.replaceExistingSubscriptions = !mKeepSubscriptions.Value(); - } - if (mFabricFiltered.HasValue()) { - params.filterByFabric = mFabricFiltered.Value(); - } - if (mAutoResubscribe.HasValue()) { - params.resubscribeAutomatically = mAutoResubscribe.Value(); - } - [cluster subscribeAttributePresetsSchedulesEditableWithParams:params - subscriptionEstablished:^() { mSubscriptionEstablished = YES; } - reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable error) { - NSLog(@"Thermostat.PresetsSchedulesEditable response %@", [value description]); - if (error == nil) { - RemoteDataModelLogger::LogAttributeAsJSON(@(endpointId), @(clusterId), @(attributeId), value); - } else { - RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); - } - SetCommandExitStatus(error); - }]; - - return CHIP_NO_ERROR; - } -}; - -#endif // MTR_ENABLE_PROVISIONAL -#if MTR_ENABLE_PROVISIONAL - /* * Attribute SetpointHoldExpiryTimestamp */ @@ -196422,13 +196270,7 @@ void registerClusterThermostat(Commands & commands) make_unique(), // #endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL - make_unique(), // -#endif // MTR_ENABLE_PROVISIONAL -#if MTR_ENABLE_PROVISIONAL - make_unique(), // -#endif // MTR_ENABLE_PROVISIONAL -#if MTR_ENABLE_PROVISIONAL - make_unique(), // + make_unique(), // #endif // MTR_ENABLE_PROVISIONAL make_unique(Id), // make_unique(Id), // @@ -196600,10 +196442,6 @@ void registerClusterThermostat(Commands & commands) make_unique(), // make_unique(), // #endif // MTR_ENABLE_PROVISIONAL -#if MTR_ENABLE_PROVISIONAL - make_unique(), // - make_unique(), // -#endif // MTR_ENABLE_PROVISIONAL #if MTR_ENABLE_PROVISIONAL make_unique(), // make_unique(), // From d31f7be6084e01a2b411b37cad81d691d4af5c0a Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Mon, 5 Aug 2024 14:47:01 -0400 Subject: [PATCH 13/41] Fix BridgedDeviceInformationCluster wildcard read (#34748) --- .../fabric-bridge-common/src/ZCLCallbacks.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp index 7a9521fa7820a7..1655df4c2f1399 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp +++ b/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp @@ -34,10 +34,9 @@ Protocols::InteractionModel::Status emberAfExternalAttributeReadCallback(Endpoin const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer, uint16_t maxReadLength) { - uint16_t endpointIndex = emberAfGetDynamicIndexFromEndpoint(endpoint); AttributeId attributeId = attributeMetadata->attributeId; - Device * dev = DeviceMgr().GetDevice(endpointIndex); + Device * dev = DeviceMgr().GetDevice(endpoint); if (dev != nullptr && clusterId == app::Clusters::BridgedDeviceBasicInformation::Id) { using namespace app::Clusters::BridgedDeviceBasicInformation::Attributes; From 653a55fc67da66f4a8f68faf5b6a98c1c00da111 Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Tue, 6 Aug 2024 13:07:04 +1200 Subject: [PATCH 14/41] Tidy up logging dependencies (#34789) * Remove workarounds for stdio logging target This is no longer needed as of #32119 * Pull in android logging in the standard way --- src/lib/support/BUILD.gn | 8 +++----- src/platform/logging/BUILD.gn | 18 ++++-------------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/lib/support/BUILD.gn b/src/lib/support/BUILD.gn index 0b1d353821dabf..38ee31fccb94e5 100644 --- a/src/lib/support/BUILD.gn +++ b/src/lib/support/BUILD.gn @@ -301,11 +301,9 @@ static_library("support") { "${chip_root}/src/inet:inet_config_header", ] - # Android has no 'platform' that provides logging - if (current_os == "android") { - public_deps += [ "${chip_root}/src/platform/android:logging" ] - } - + # Platforms that utilize CHIP_SYSTEM_CONFIG_PLATFORM_LOG need to + # be pulled in here as public_deps since they hook into logging at + # the macro level rather than just providing a LogV implementation. if (current_os == "mac" || current_os == "ios") { public_deps += [ "${chip_root}/src/platform/Darwin:logging" ] } diff --git a/src/platform/logging/BUILD.gn b/src/platform/logging/BUILD.gn index bc41c12da17e88..9b26f40569f428 100644 --- a/src/platform/logging/BUILD.gn +++ b/src/platform/logging/BUILD.gn @@ -76,10 +76,11 @@ source_set("default") { deps += [ ":stdio" ] } else if (chip_device_platform == "nuttx") { deps += [ "${chip_root}/src/platform/NuttX:logging" ] + } else if (chip_device_platform == "android") { + deps += [ "${chip_root}/src/platform/android:logging" ] } else { - assert( - chip_device_platform == "fake" || chip_device_platform == "android" || - chip_device_platform == "external" || chip_device_platform == "none") + assert(chip_device_platform == "fake" || + chip_device_platform == "external" || chip_device_platform == "none") } } } @@ -88,11 +89,6 @@ source_set("headers") { public = [ "LogV.h" ] } -# We need to reference the output file of ":stdio" at build time, -# but get_target_outputs() does not work for binary targets. As a -# workaround, define a reasonable path and make the target use it. -stdio_archive = "$root_out_dir/liblogging-stdio.a" - source_set("stdio") { sources = [ "impl/stdio/Logging.cpp" ] @@ -104,10 +100,4 @@ source_set("stdio") { "${chip_root}/src/platform:platform_config_header", "${chip_root}/src/platform/logging:headers", ] - - # Ensure we end up with the expected output file name - output_dir = get_path_info(stdio_archive, "dir") - output_name = get_path_info(stdio_archive, "name") - output_extension = get_path_info(stdio_archive, "extension") - output_prefix_override = true } From e2ce4030c39b6ad3783ca7c0216c333ce6fef9c7 Mon Sep 17 00:00:00 2001 From: Nivi Sarkar <55898241+nivi-apple@users.noreply.github.com> Date: Tue, 6 Aug 2024 01:12:02 -0700 Subject: [PATCH 15/41] Replace ChipErrorFromStatusCode with CHIP_ERROR_IM_GLOBAL_STATUS_VALUE (#34781) --- examples/thermostat/linux/thermostat-manager.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/examples/thermostat/linux/thermostat-manager.cpp b/examples/thermostat/linux/thermostat-manager.cpp index 90d4588a131ca6..ea1f4375c1649d 100644 --- a/examples/thermostat/linux/thermostat-manager.cpp +++ b/examples/thermostat/linux/thermostat-manager.cpp @@ -61,12 +61,6 @@ ThermostatManager ThermostatManager::sThermostatMgr; namespace { -CHIP_ERROR ChipErrorFromStatusCode(Status status) -{ - StatusIB statusIB(status); - return statusIB.ToChipError(); -} - template static void OnAttributeChangeReported(const ConcreteDataAttributePath & path, const DecodableAttributeType & value); @@ -332,7 +326,7 @@ CHIP_ERROR ThermostatManager::SetSystemMode(SystemModeEnum systemMode) } ChipLogError(AppServer, "Setting system mode: %u (%s)", systemModeValue, SystemModeString(systemMode)); - return ChipErrorFromStatusCode(SystemMode::Set(kThermostatEndpoint, systemMode)); + return CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(SystemMode::Set(kThermostatEndpoint, systemMode)); } CHIP_ERROR ThermostatManager::SetRunningMode(ThermostatRunningModeEnum runningMode) @@ -345,22 +339,22 @@ CHIP_ERROR ThermostatManager::SetRunningMode(ThermostatRunningModeEnum runningMo } ChipLogError(AppServer, "Setting running mode: %u (%s)", runningModeValue, RunningModeString(runningMode)); - return ChipErrorFromStatusCode(ThermostatRunningMode::Set(kThermostatEndpoint, runningMode)); + return CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(ThermostatRunningMode::Set(kThermostatEndpoint, runningMode)); } CHIP_ERROR ThermostatManager::SetCurrentTemperature(int16_t temperature) { - return ChipErrorFromStatusCode(LocalTemperature::Set(kThermostatEndpoint, temperature)); + return CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(LocalTemperature::Set(kThermostatEndpoint, temperature)); } CHIP_ERROR ThermostatManager::SetCurrentHeatingSetPoint(int16_t heatingSetpoint) { - return ChipErrorFromStatusCode(OccupiedHeatingSetpoint::Set(kThermostatEndpoint, heatingSetpoint)); + return CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(OccupiedHeatingSetpoint::Set(kThermostatEndpoint, heatingSetpoint)); } CHIP_ERROR ThermostatManager::SetCurrentCoolingSetPoint(int16_t coolingSetpoint) { - return ChipErrorFromStatusCode(OccupiedCoolingSetpoint::Set(kThermostatEndpoint, coolingSetpoint)); + return CHIP_ERROR_IM_GLOBAL_STATUS_VALUE(OccupiedCoolingSetpoint::Set(kThermostatEndpoint, coolingSetpoint)); } void ThermostatManager::EvalThermostatState() From f17d486118fd77f7801cb4b73ba30e8d02bbb9c3 Mon Sep 17 00:00:00 2001 From: William Date: Tue, 6 Aug 2024 10:12:22 +0100 Subject: [PATCH 16/41] Create relative position namespace (#34701) * Updated the golabl data type's XMLs, removing the cluster entries. * Zap generated after XML update. * Fixed namespaces used of global structs. * Restyled by clang-format * Defined the RelativePosition namespace in the namespaces XML. * Zap generated after XML update. * Zap generated after sync. * Fixed the rvc-example that was using the PositionTag type. --------- Co-authored-by: Restyled.io --- .../air-purifier-app.matter | 17 ++++---- .../air-quality-sensor-app.matter | 17 ++++---- .../all-clusters-app.matter | 17 ++++---- .../all-clusters-minimal-app.matter | 17 ++++---- .../bridge-common/bridge-app.matter | 17 ++++---- ...p_rootnode_dimmablelight_bCwGYSDpoe.matter | 17 ++++---- .../rootnode_airpurifier_73a6fe2651.matter | 17 ++++---- ...umiditysensor_thermostat_56de3d5f45.matter | 17 ++++---- ...ootnode_airqualitysensor_e63187f6c9.matter | 17 ++++---- ...ootnode_basicvideoplayer_0ff86e943b.matter | 17 ++++---- ...de_colortemperaturelight_hbUnzYVeyn.matter | 17 ++++---- .../rootnode_contactsensor_27f76aeaf5.matter | 17 ++++---- .../rootnode_contactsensor_lFAGG1bfRO.matter | 17 ++++---- .../rootnode_dimmablelight_bCwGYSDpoe.matter | 17 ++++---- ...tnode_dimmablepluginunit_f8a9a0b9d4.matter | 17 ++++---- .../rootnode_dishwasher_cc105034fe.matter | 17 ++++---- .../rootnode_doorlock_aNKYAreMXE.matter | 17 ++++---- ...tnode_extendedcolorlight_8lcaaYJVAa.matter | 17 ++++---- .../devices/rootnode_fan_7N2TobIlOX.matter | 17 ++++---- .../rootnode_flowsensor_1zVxHedlaV.matter | 17 ++++---- .../rootnode_genericswitch_2dfff6e516.matter | 17 ++++---- .../rootnode_genericswitch_9866e35d0b.matter | 17 ++++---- ...tnode_heatingcoolingunit_ncdGai1E5a.matter | 17 ++++---- .../rootnode_humiditysensor_Xyj4gda6Hb.matter | 17 ++++---- .../rootnode_laundrywasher_fb10d238c8.matter | 17 ++++---- .../rootnode_lightsensor_lZQycTFcJK.matter | 17 ++++---- ...rootnode_occupancysensor_iHyVgifZuo.matter | 17 ++++---- .../rootnode_onofflight_bbs1b7IaOV.matter | 17 ++++---- .../rootnode_onofflight_samplemei.matter | 17 ++++---- ...ootnode_onofflightswitch_FsPlMr090Q.matter | 17 ++++---- ...rootnode_onoffpluginunit_Wtf8ss5EBY.matter | 17 ++++---- .../rootnode_pressuresensor_s0qC9wLH4k.matter | 17 ++++---- .../devices/rootnode_pump_5f904818cc.matter | 17 ++++---- .../devices/rootnode_pump_a811bb33a0.matter | 17 ++++---- ...eraturecontrolledcabinet_ffdb696680.matter | 17 ++++---- ...ode_roboticvacuumcleaner_1807ff0c49.matter | 17 ++++---- ...tnode_roomairconditioner_9cf3607804.matter | 17 ++++---- .../rootnode_smokecoalarm_686fe0dcb8.matter | 17 ++++---- .../rootnode_speaker_RpzeXdimqA.matter | 17 ++++---- ...otnode_temperaturesensor_Qy1zkNW7c3.matter | 17 ++++---- .../rootnode_thermostat_bm3fb8dhYi.matter | 17 ++++---- .../rootnode_windowcovering_RLCxaGi9Yx.matter | 17 ++++---- .../contact-sensor-app.matter | 17 ++++---- .../nxp/zap-lit/contact-sensor-app.matter | 17 ++++---- .../nxp/zap-sit/contact-sensor-app.matter | 17 ++++---- .../dishwasher-common/dishwasher-app.matter | 17 ++++---- .../energy-management-app.matter | 17 ++++---- .../fabric-bridge-app.matter | 17 ++++---- .../nxp/zap/laundry-washer-app.matter | 17 ++++---- .../light-switch-app.matter | 17 ++++---- .../light-switch-app/qpg/zap/switch.matter | 17 ++++---- .../data_model/lighting-app-ethernet.matter | 17 ++++---- .../data_model/lighting-app-thread.matter | 17 ++++---- .../data_model/lighting-app-wifi.matter | 17 ++++---- .../lighting-common/lighting-app.matter | 17 ++++---- .../nxp/zap/lighting-on-off.matter | 17 ++++---- examples/lighting-app/qpg/zap/light.matter | 17 ++++---- .../data_model/lighting-thread-app.matter | 17 ++++---- .../data_model/lighting-wifi-app.matter | 17 ++++---- .../lit-icd-common/lit-icd-server-app.matter | 17 ++++---- examples/lock-app/lock-common/lock-app.matter | 17 ++++---- examples/lock-app/nxp/zap/lock-app.matter | 17 ++++---- examples/lock-app/qpg/zap/lock.matter | 17 ++++---- .../log-source-common/log-source-app.matter | 17 ++++---- .../microwave-oven-app.matter | 17 ++++---- .../network-manager-app.matter | 17 ++++---- .../ota-provider-app.matter | 17 ++++---- .../ota-requestor-app.matter | 17 ++++---- .../placeholder/linux/apps/app1/config.matter | 17 ++++---- .../placeholder/linux/apps/app2/config.matter | 17 ++++---- examples/pump-app/pump-common/pump-app.matter | 17 ++++---- .../silabs/data_model/pump-thread-app.matter | 17 ++++---- .../silabs/data_model/pump-wifi-app.matter | 17 ++++---- .../pump-controller-app.matter | 17 ++++---- .../refrigerator-app.matter | 17 ++++---- examples/rvc-app/rvc-common/rvc-app.matter | 17 ++++---- .../src/rvc-service-area-delegate.cpp | 4 +- .../smoke-co-alarm-app.matter | 17 ++++---- .../temperature-measurement.matter | 17 ++++---- .../nxp/zap/thermostat_matter_thread.matter | 17 ++++---- .../nxp/zap/thermostat_matter_wifi.matter | 17 ++++---- .../qpg/zap/thermostaticRadiatorValve.matter | 17 ++++---- .../thermostat-common/thermostat.matter | 17 ++++---- examples/tv-app/tv-common/tv-app.matter | 17 ++++---- .../tv-casting-common/tv-casting-app.matter | 17 ++++---- .../virtual-device-app.matter | 17 ++++---- examples/window-app/common/window-app.matter | 17 ++++---- .../chip/semantic-tag-namespace-enums.xml | 17 ++++---- .../data_model/controller-clusters.matter | 17 ++++---- .../python/chip/clusters/Objects.py | 23 +++++++---- .../CHIP/zap-generated/MTRBaseClusters.h | 17 ++++---- .../zap-generated/cluster-enums-check.h | 25 ++++++++---- .../app-common/zap-generated/cluster-enums.h | 40 ++++++++++++------- 93 files changed, 950 insertions(+), 655 deletions(-) diff --git a/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter b/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter index c79eacc2037129..cb1c102b239f3e 100644 --- a/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter +++ b/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/air-quality-sensor-app/air-quality-sensor-common/air-quality-sensor-app.matter b/examples/air-quality-sensor-app/air-quality-sensor-common/air-quality-sensor-app.matter index d7667f228ef2e0..0566f91f67a953 100644 --- a/examples/air-quality-sensor-app/air-quality-sensor-common/air-quality-sensor-app.matter +++ b/examples/air-quality-sensor-app/air-quality-sensor-common/air-quality-sensor-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { 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 795f470b88a6a8..76c150be26d933 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 @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { 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 223b572d025cb0..fcb987edb574aa 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 @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/bridge-app/bridge-common/bridge-app.matter b/examples/bridge-app/bridge-common/bridge-app.matter index de25428864fbe4..1cc37299be6645 100644 --- a/examples/bridge-app/bridge-common/bridge-app.matter +++ b/examples/bridge-app/bridge-common/bridge-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter b/examples/chef/devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter index 40e5bb05b9bb08..5edebd77931b80 100644 --- a/examples/chef/devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter +++ b/examples/chef/devices/noip_rootnode_dimmablelight_bCwGYSDpoe.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter b/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter index 47399bbe07fedf..e4584f1ee4d086 100644 --- a/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter +++ b/examples/chef/devices/rootnode_airpurifier_73a6fe2651.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter b/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter index 159ab6e2a8b5b6..ed130f29318062 100644 --- a/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter +++ b/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter b/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter index 5c54416f886d68..e155c0bb946563 100644 --- a/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter +++ b/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter index 4a925bdf876f45..84f789e40a1110 100644 --- a/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter +++ b/examples/chef/devices/rootnode_basicvideoplayer_0ff86e943b.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter b/examples/chef/devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter index 7ce3ee0dc39630..961f40352b1052 100644 --- a/examples/chef/devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter +++ b/examples/chef/devices/rootnode_colortemperaturelight_hbUnzYVeyn.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter b/examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter index 66dd9f6c2cff51..d10dce747c4695 100644 --- a/examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter +++ b/examples/chef/devices/rootnode_contactsensor_27f76aeaf5.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter b/examples/chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter index 72ade2bfbabea7..eff62c6119120c 100644 --- a/examples/chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter +++ b/examples/chef/devices/rootnode_contactsensor_lFAGG1bfRO.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter b/examples/chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter index 424388a3bc3369..8b8c2003f7bc29 100644 --- a/examples/chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter +++ b/examples/chef/devices/rootnode_dimmablelight_bCwGYSDpoe.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter b/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter index d0a9913df155a1..0bf5f933e3d543 100644 --- a/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter +++ b/examples/chef/devices/rootnode_dimmablepluginunit_f8a9a0b9d4.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_dishwasher_cc105034fe.matter b/examples/chef/devices/rootnode_dishwasher_cc105034fe.matter index 4fe29a645d9e6e..c8e41990993d27 100644 --- a/examples/chef/devices/rootnode_dishwasher_cc105034fe.matter +++ b/examples/chef/devices/rootnode_dishwasher_cc105034fe.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter b/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter index 90292d1ea06c4e..1369028c39df4f 100644 --- a/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter +++ b/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter b/examples/chef/devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter index d4cea1c3c63b8c..d9841f769a79dd 100644 --- a/examples/chef/devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter +++ b/examples/chef/devices/rootnode_extendedcolorlight_8lcaaYJVAa.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter b/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter index 7ea73610feaa7b..05a176ee9ab710 100644 --- a/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter +++ b/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter b/examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter index ad880498571bc0..93eac702dcbc06 100644 --- a/examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter +++ b/examples/chef/devices/rootnode_flowsensor_1zVxHedlaV.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter b/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter index 100ee17a1b84c7..8748b8cd13b81f 100644 --- a/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter +++ b/examples/chef/devices/rootnode_genericswitch_2dfff6e516.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter b/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter index 979b8046ce7901..4c8e67c11e7726 100644 --- a/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter +++ b/examples/chef/devices/rootnode_genericswitch_9866e35d0b.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter index 6ec3535eae0302..ec62d4504f8601 100644 --- a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter +++ b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter b/examples/chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter index 1918e417c2b725..adc500a4771045 100644 --- a/examples/chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter +++ b/examples/chef/devices/rootnode_humiditysensor_Xyj4gda6Hb.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_laundrywasher_fb10d238c8.matter b/examples/chef/devices/rootnode_laundrywasher_fb10d238c8.matter index e327a8eb68ae75..06e8ba84d349b6 100644 --- a/examples/chef/devices/rootnode_laundrywasher_fb10d238c8.matter +++ b/examples/chef/devices/rootnode_laundrywasher_fb10d238c8.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter b/examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter index c801a97df380ee..be3a039189a5ed 100644 --- a/examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter +++ b/examples/chef/devices/rootnode_lightsensor_lZQycTFcJK.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter b/examples/chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter index 0a9039409289e1..c12fe40a360ea7 100644 --- a/examples/chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter +++ b/examples/chef/devices/rootnode_occupancysensor_iHyVgifZuo.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter b/examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter index 05bd1e0dc4552d..4627385f5a4c44 100644 --- a/examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter +++ b/examples/chef/devices/rootnode_onofflight_bbs1b7IaOV.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_onofflight_samplemei.matter b/examples/chef/devices/rootnode_onofflight_samplemei.matter index dfd0b1a07bf478..90131350b3ca47 100644 --- a/examples/chef/devices/rootnode_onofflight_samplemei.matter +++ b/examples/chef/devices/rootnode_onofflight_samplemei.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter b/examples/chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter index e6b65b5f357f8a..cffe70d9aab388 100644 --- a/examples/chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter +++ b/examples/chef/devices/rootnode_onofflightswitch_FsPlMr090Q.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter b/examples/chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter index 95e0efdc1ce319..a5e0f5505dffd8 100644 --- a/examples/chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter +++ b/examples/chef/devices/rootnode_onoffpluginunit_Wtf8ss5EBY.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter b/examples/chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter index b447bcaf9fd30d..2b9b4036e638f5 100644 --- a/examples/chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter +++ b/examples/chef/devices/rootnode_pressuresensor_s0qC9wLH4k.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_pump_5f904818cc.matter b/examples/chef/devices/rootnode_pump_5f904818cc.matter index 905099c03e2b8d..cf42feded0cee8 100644 --- a/examples/chef/devices/rootnode_pump_5f904818cc.matter +++ b/examples/chef/devices/rootnode_pump_5f904818cc.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_pump_a811bb33a0.matter b/examples/chef/devices/rootnode_pump_a811bb33a0.matter index 9e13f678310b78..78ae33bc847e5d 100644 --- a/examples/chef/devices/rootnode_pump_a811bb33a0.matter +++ b/examples/chef/devices/rootnode_pump_a811bb33a0.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_refrigerator_temperaturecontrolledcabinet_temperaturecontrolledcabinet_ffdb696680.matter b/examples/chef/devices/rootnode_refrigerator_temperaturecontrolledcabinet_temperaturecontrolledcabinet_ffdb696680.matter index b2e81d6229586e..7d8c54a3f41c4c 100644 --- a/examples/chef/devices/rootnode_refrigerator_temperaturecontrolledcabinet_temperaturecontrolledcabinet_ffdb696680.matter +++ b/examples/chef/devices/rootnode_refrigerator_temperaturecontrolledcabinet_temperaturecontrolledcabinet_ffdb696680.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter b/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter index 3b08c19cf02ed2..d53a594c514919 100644 --- a/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter +++ b/examples/chef/devices/rootnode_roboticvacuumcleaner_1807ff0c49.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter b/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter index b01b11f56f8c58..95e0ba20d4adcb 100644 --- a/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter +++ b/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter b/examples/chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter index 8be645e41ddfea..3408fc64e6fc6f 100644 --- a/examples/chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter +++ b/examples/chef/devices/rootnode_smokecoalarm_686fe0dcb8.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter b/examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter index 400606024bbb02..bf55ae4be3bf03 100644 --- a/examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter +++ b/examples/chef/devices/rootnode_speaker_RpzeXdimqA.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter b/examples/chef/devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter index 3132bdb15686b3..b3178232de0291 100644 --- a/examples/chef/devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter +++ b/examples/chef/devices/rootnode_temperaturesensor_Qy1zkNW7c3.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter index 751529c70dbb5c..6c27235c7d3ade 100644 --- a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter +++ b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter b/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter index 3851f1d0328f32..f49ed5824d5ce4 100644 --- a/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter +++ b/examples/chef/devices/rootnode_windowcovering_RLCxaGi9Yx.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/contact-sensor-app/contact-sensor-common/contact-sensor-app.matter b/examples/contact-sensor-app/contact-sensor-common/contact-sensor-app.matter index ee218d61684d4b..4baa8d22887c32 100644 --- a/examples/contact-sensor-app/contact-sensor-common/contact-sensor-app.matter +++ b/examples/contact-sensor-app/contact-sensor-common/contact-sensor-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter b/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter index 44bf8425d7a88a..4a3e015ddedb5c 100644 --- a/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter +++ b/examples/contact-sensor-app/nxp/zap-lit/contact-sensor-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter b/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter index cf2bee67f6da02..d8d2734e60a98b 100644 --- a/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter +++ b/examples/contact-sensor-app/nxp/zap-sit/contact-sensor-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/dishwasher-app/dishwasher-common/dishwasher-app.matter b/examples/dishwasher-app/dishwasher-common/dishwasher-app.matter index df35f214119b69..661a2e74de4f4e 100644 --- a/examples/dishwasher-app/dishwasher-common/dishwasher-app.matter +++ b/examples/dishwasher-app/dishwasher-common/dishwasher-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/energy-management-app/energy-management-common/energy-management-app.matter b/examples/energy-management-app/energy-management-common/energy-management-app.matter index 22b17a3b7dd58c..e7fba7e08e028f 100644 --- a/examples/energy-management-app/energy-management-common/energy-management-app.matter +++ b/examples/energy-management-app/energy-management-common/energy-management-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter b/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter index 9294f0f069c57d..3fb7436adbfe5a 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter +++ b/examples/fabric-bridge-app/fabric-bridge-common/fabric-bridge-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter b/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter index b993fe9100e101..7ecbd20a6e9d0f 100644 --- a/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter +++ b/examples/laundry-washer-app/nxp/zap/laundry-washer-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/light-switch-app/light-switch-common/light-switch-app.matter b/examples/light-switch-app/light-switch-common/light-switch-app.matter index d9aa1313f34c0b..8cd9c653a75bb5 100644 --- a/examples/light-switch-app/light-switch-common/light-switch-app.matter +++ b/examples/light-switch-app/light-switch-common/light-switch-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/light-switch-app/qpg/zap/switch.matter b/examples/light-switch-app/qpg/zap/switch.matter index 002943282c94bd..6924e96503d0c6 100644 --- a/examples/light-switch-app/qpg/zap/switch.matter +++ b/examples/light-switch-app/qpg/zap/switch.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/lighting-app/bouffalolab/data_model/lighting-app-ethernet.matter b/examples/lighting-app/bouffalolab/data_model/lighting-app-ethernet.matter index 010ba4d1dc88a8..331f7e79cadfe9 100644 --- a/examples/lighting-app/bouffalolab/data_model/lighting-app-ethernet.matter +++ b/examples/lighting-app/bouffalolab/data_model/lighting-app-ethernet.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/lighting-app/bouffalolab/data_model/lighting-app-thread.matter b/examples/lighting-app/bouffalolab/data_model/lighting-app-thread.matter index ae6ed8acaef557..f6bb26ec689619 100644 --- a/examples/lighting-app/bouffalolab/data_model/lighting-app-thread.matter +++ b/examples/lighting-app/bouffalolab/data_model/lighting-app-thread.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/lighting-app/bouffalolab/data_model/lighting-app-wifi.matter b/examples/lighting-app/bouffalolab/data_model/lighting-app-wifi.matter index 49f5f4f007adc9..9dee0bdcdb040d 100644 --- a/examples/lighting-app/bouffalolab/data_model/lighting-app-wifi.matter +++ b/examples/lighting-app/bouffalolab/data_model/lighting-app-wifi.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/lighting-app/lighting-common/lighting-app.matter b/examples/lighting-app/lighting-common/lighting-app.matter index 48650af7462729..8bdaaedaa68ce6 100644 --- a/examples/lighting-app/lighting-common/lighting-app.matter +++ b/examples/lighting-app/lighting-common/lighting-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/lighting-app/nxp/zap/lighting-on-off.matter b/examples/lighting-app/nxp/zap/lighting-on-off.matter index 4da56bd6ddff25..1f88cfb7687610 100644 --- a/examples/lighting-app/nxp/zap/lighting-on-off.matter +++ b/examples/lighting-app/nxp/zap/lighting-on-off.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/lighting-app/qpg/zap/light.matter b/examples/lighting-app/qpg/zap/light.matter index b27ac3d90820da..6add567a134707 100644 --- a/examples/lighting-app/qpg/zap/light.matter +++ b/examples/lighting-app/qpg/zap/light.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/lighting-app/silabs/data_model/lighting-thread-app.matter b/examples/lighting-app/silabs/data_model/lighting-thread-app.matter index 473d0c1efd44b9..d0e06e94f94dac 100644 --- a/examples/lighting-app/silabs/data_model/lighting-thread-app.matter +++ b/examples/lighting-app/silabs/data_model/lighting-thread-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter b/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter index 38091dbe0ccbe0..a9d48f8ae85b3c 100644 --- a/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter +++ b/examples/lighting-app/silabs/data_model/lighting-wifi-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter index 5d2ede841e2fcd..e76ccb9372798d 100644 --- a/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter +++ b/examples/lit-icd-app/lit-icd-common/lit-icd-server-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/lock-app/lock-common/lock-app.matter b/examples/lock-app/lock-common/lock-app.matter index aca989e2c43440..a925bf75f55255 100644 --- a/examples/lock-app/lock-common/lock-app.matter +++ b/examples/lock-app/lock-common/lock-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/lock-app/nxp/zap/lock-app.matter b/examples/lock-app/nxp/zap/lock-app.matter index 528412e523b0a0..cb2cbcc52f3263 100644 --- a/examples/lock-app/nxp/zap/lock-app.matter +++ b/examples/lock-app/nxp/zap/lock-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/lock-app/qpg/zap/lock.matter b/examples/lock-app/qpg/zap/lock.matter index b38d2b96b27509..ee7a955db20f4b 100644 --- a/examples/lock-app/qpg/zap/lock.matter +++ b/examples/lock-app/qpg/zap/lock.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/log-source-app/log-source-common/log-source-app.matter b/examples/log-source-app/log-source-common/log-source-app.matter index c9af17203111cf..e9baa7757f53eb 100644 --- a/examples/log-source-app/log-source-common/log-source-app.matter +++ b/examples/log-source-app/log-source-common/log-source-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter b/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter index 4c36a56025829e..cea8d411735738 100644 --- a/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter +++ b/examples/microwave-oven-app/microwave-oven-common/microwave-oven-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/network-manager-app/network-manager-common/network-manager-app.matter b/examples/network-manager-app/network-manager-common/network-manager-app.matter index 89200240662d70..bbd20d46b43d94 100644 --- a/examples/network-manager-app/network-manager-common/network-manager-app.matter +++ b/examples/network-manager-app/network-manager-common/network-manager-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter b/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter index 6746a5ba516104..a066629c9f4ae1 100644 --- a/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter +++ b/examples/ota-provider-app/ota-provider-common/ota-provider-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter b/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter index da22094fd2e8c3..3412f30a29b1f9 100644 --- a/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter +++ b/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/placeholder/linux/apps/app1/config.matter b/examples/placeholder/linux/apps/app1/config.matter index 83d5c9745f5e9a..87b61c8a45357c 100644 --- a/examples/placeholder/linux/apps/app1/config.matter +++ b/examples/placeholder/linux/apps/app1/config.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/placeholder/linux/apps/app2/config.matter b/examples/placeholder/linux/apps/app2/config.matter index 00b620e45fa55b..db46fa85d7e71d 100644 --- a/examples/placeholder/linux/apps/app2/config.matter +++ b/examples/placeholder/linux/apps/app2/config.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/pump-app/pump-common/pump-app.matter b/examples/pump-app/pump-common/pump-app.matter index 4482329a1245e4..c99a5c2f2c7782 100644 --- a/examples/pump-app/pump-common/pump-app.matter +++ b/examples/pump-app/pump-common/pump-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/pump-app/silabs/data_model/pump-thread-app.matter b/examples/pump-app/silabs/data_model/pump-thread-app.matter index ec9b0e09f0318d..4327438f220783 100644 --- a/examples/pump-app/silabs/data_model/pump-thread-app.matter +++ b/examples/pump-app/silabs/data_model/pump-thread-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/pump-app/silabs/data_model/pump-wifi-app.matter b/examples/pump-app/silabs/data_model/pump-wifi-app.matter index ec9b0e09f0318d..4327438f220783 100644 --- a/examples/pump-app/silabs/data_model/pump-wifi-app.matter +++ b/examples/pump-app/silabs/data_model/pump-wifi-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter b/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter index 74c2fbd6ca67ff..7365654ce9c65b 100644 --- a/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter +++ b/examples/pump-controller-app/pump-controller-common/pump-controller-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/refrigerator-app/refrigerator-common/refrigerator-app.matter b/examples/refrigerator-app/refrigerator-common/refrigerator-app.matter index 73036faa89b9da..f028a3b31557c5 100644 --- a/examples/refrigerator-app/refrigerator-common/refrigerator-app.matter +++ b/examples/refrigerator-app/refrigerator-common/refrigerator-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/rvc-app/rvc-common/rvc-app.matter b/examples/rvc-app/rvc-common/rvc-app.matter index 8342817b1321e9..596fde4138576a 100644 --- a/examples/rvc-app/rvc-common/rvc-app.matter +++ b/examples/rvc-app/rvc-common/rvc-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/rvc-app/rvc-common/src/rvc-service-area-delegate.cpp b/examples/rvc-app/rvc-common/src/rvc-service-area-delegate.cpp index 977189032b3e27..e46d3eaa22dff7 100644 --- a/examples/rvc-app/rvc-common/src/rvc-service-area-delegate.cpp +++ b/examples/rvc-app/rvc-common/src/rvc-service-area-delegate.cpp @@ -54,7 +54,7 @@ CHIP_ERROR RvcServiceAreaDelegate::Init() DataModel::Nullable(-1), DataModel::Nullable(Globals::AreaTypeTag::kPlayRoom), DataModel::Nullable(Globals::LandmarkTag::kBackDoor), - DataModel::Nullable(Globals::PositionTag::kNextTo), + DataModel::Nullable(Globals::PositionTag::kLeft), DataModel::Nullable(Globals::FloorSurfaceTag::kConcrete)); // Location D has null values for all HomeLocationStruct fields, Map YY @@ -62,7 +62,7 @@ CHIP_ERROR RvcServiceAreaDelegate::Init() "My Location D"_span, DataModel::Nullable(), DataModel::Nullable(), DataModel::Nullable(Globals::LandmarkTag::kCouch), - DataModel::Nullable(Globals::PositionTag::kNextTo), + DataModel::Nullable(Globals::PositionTag::kLeft), DataModel::Nullable(Globals::FloorSurfaceTag::kHardwood)); GetInstance()->SetCurrentArea(supportedAreaID_C); diff --git a/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter b/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter index 71aa847401e521..21d1cebf065fb4 100644 --- a/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter +++ b/examples/smoke-co-alarm-app/smoke-co-alarm-common/smoke-co-alarm-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter b/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter index 3b41b5a099ac0f..4ebc3dc672d48f 100644 --- a/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter +++ b/examples/temperature-measurement-app/temperature-measurement-common/temperature-measurement.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/thermostat/nxp/zap/thermostat_matter_thread.matter b/examples/thermostat/nxp/zap/thermostat_matter_thread.matter index b85de2986ffd44..001e1b43ace09d 100644 --- a/examples/thermostat/nxp/zap/thermostat_matter_thread.matter +++ b/examples/thermostat/nxp/zap/thermostat_matter_thread.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/thermostat/nxp/zap/thermostat_matter_wifi.matter b/examples/thermostat/nxp/zap/thermostat_matter_wifi.matter index 1cdce376d85543..066afc85509947 100644 --- a/examples/thermostat/nxp/zap/thermostat_matter_wifi.matter +++ b/examples/thermostat/nxp/zap/thermostat_matter_wifi.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter b/examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter index 8da05509bed572..31e5775d88148f 100644 --- a/examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter +++ b/examples/thermostat/qpg/zap/thermostaticRadiatorValve.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/thermostat/thermostat-common/thermostat.matter b/examples/thermostat/thermostat-common/thermostat.matter index dc4b0a886108ab..a53e3cdc692952 100644 --- a/examples/thermostat/thermostat-common/thermostat.matter +++ b/examples/thermostat/thermostat-common/thermostat.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/tv-app/tv-common/tv-app.matter b/examples/tv-app/tv-common/tv-app.matter index 6401ae8dad4ba9..34aa4475c79677 100644 --- a/examples/tv-app/tv-common/tv-app.matter +++ b/examples/tv-app/tv-common/tv-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter b/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter index f0e6fec3c429bb..02aadc0439b50a 100644 --- a/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter +++ b/examples/tv-casting-app/tv-casting-common/tv-casting-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter b/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter index 319a66e0ba83ea..135846fd606d48 100644 --- a/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter +++ b/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/examples/window-app/common/window-app.matter b/examples/window-app/common/window-app.matter index 17a6bc61bcd3d3..f31a1917a5fd0e 100644 --- a/examples/window-app/common/window-app.matter +++ b/examples/window-app/common/window-app.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/src/app/zap-templates/zcl/data-model/chip/semantic-tag-namespace-enums.xml b/src/app/zap-templates/zcl/data-model/chip/semantic-tag-namespace-enums.xml index b79a5398d78bdb..be34b3c86f32ab 100644 --- a/src/app/zap-templates/zcl/data-model/chip/semantic-tag-namespace-enums.xml +++ b/src/app/zap-templates/zcl/data-model/chip/semantic-tag-namespace-enums.xml @@ -25,13 +25,16 @@ limitations under the License. - - - - - - - + + + + + + + + + + diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 2954d22de36479..589f832c0ca39b 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -194,13 +194,16 @@ enum PositionTag : enum8 { kMiddle = 4; kRow = 5; kColumn = 6; - kUnder = 7; - kNextTo = 8; - kAround = 9; - kOn = 10; - kAbove = 11; - kFrontOf = 12; - kBehind = 13; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; } enum TestGlobalEnum : enum8 { diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index ec5928318d97e7..5f1ca74314b3a3 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -247,18 +247,25 @@ class PositionTag(MatterIntEnum): kMiddle = 0x04 kRow = 0x05 kColumn = 0x06 - kUnder = 0x07 - kNextTo = 0x08 - kAround = 0x09 - kOn = 0x0A - kAbove = 0x0B - kFrontOf = 0x0C - kBehind = 0x0D # All received enum values that are not listed above will be mapped # to kUnknownEnumValue. This is a helper enum value that should only # be used by code to process how it handles receiving an unknown # enum value. This specific value should never be transmitted. - kUnknownEnumValue = 14, + kUnknownEnumValue = 7, + + class RelativePositionTag(MatterIntEnum): + kUnder = 0x00 + kNextTo = 0x01 + kAround = 0x02 + kOn = 0x03 + kAbove = 0x04 + kFrontOf = 0x05 + kBehind = 0x06 + # All received enum values that are not listed above will be mapped + # to kUnknownEnumValue. This is a helper enum value that should only + # be used by code to process how it handles receiving an unknown + # enum value. This specific value should never be transmitted. + kUnknownEnumValue = 7, class TestGlobalEnum(MatterIntEnum): kSomeValue = 0x00 diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index 21b7a81cb5746f..b8dfaa140e03e3 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -17381,13 +17381,16 @@ typedef NS_ENUM(uint8_t, MTRDataTypePositionTag) { MTRDataTypePositionTagMiddle MTR_PROVISIONALLY_AVAILABLE = 0x04, MTRDataTypePositionTagRow MTR_PROVISIONALLY_AVAILABLE = 0x05, MTRDataTypePositionTagColumn MTR_PROVISIONALLY_AVAILABLE = 0x06, - MTRDataTypePositionTagUnder MTR_PROVISIONALLY_AVAILABLE = 0x07, - MTRDataTypePositionTagNextTo MTR_PROVISIONALLY_AVAILABLE = 0x08, - MTRDataTypePositionTagAround MTR_PROVISIONALLY_AVAILABLE = 0x09, - MTRDataTypePositionTagOn MTR_PROVISIONALLY_AVAILABLE = 0x0A, - MTRDataTypePositionTagAbove MTR_PROVISIONALLY_AVAILABLE = 0x0B, - MTRDataTypePositionTagFrontOf MTR_PROVISIONALLY_AVAILABLE = 0x0C, - MTRDataTypePositionTagBehind MTR_PROVISIONALLY_AVAILABLE = 0x0D, +} MTR_PROVISIONALLY_AVAILABLE; + +typedef NS_ENUM(uint8_t, MTRDataTypeRelativePositionTag) { + MTRDataTypeRelativePositionTagUnder MTR_PROVISIONALLY_AVAILABLE = 0x00, + MTRDataTypeRelativePositionTagNextTo MTR_PROVISIONALLY_AVAILABLE = 0x01, + MTRDataTypeRelativePositionTagAround MTR_PROVISIONALLY_AVAILABLE = 0x02, + MTRDataTypeRelativePositionTagOn MTR_PROVISIONALLY_AVAILABLE = 0x03, + MTRDataTypeRelativePositionTagAbove MTR_PROVISIONALLY_AVAILABLE = 0x04, + MTRDataTypeRelativePositionTagFrontOf MTR_PROVISIONALLY_AVAILABLE = 0x05, + MTRDataTypeRelativePositionTagBehind MTR_PROVISIONALLY_AVAILABLE = 0x06, } MTR_PROVISIONALLY_AVAILABLE; typedef NS_ENUM(uint8_t, MTRDataTypeTestGlobalEnum) { diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h index c32cf146b0da8b..8a951e2a54a575 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h @@ -377,13 +377,6 @@ static auto __attribute__((unused)) EnsureKnownEnumValue(Globals::PositionTag va case EnumType::kMiddle: case EnumType::kRow: case EnumType::kColumn: - case EnumType::kUnder: - case EnumType::kNextTo: - case EnumType::kAround: - case EnumType::kOn: - case EnumType::kAbove: - case EnumType::kFrontOf: - case EnumType::kBehind: return val; default: return EnumType::kUnknownEnumValue; @@ -405,6 +398,24 @@ static auto __attribute__((unused)) EnsureKnownEnumValue(detail::ProductIdentifi return EnumType::kUnknownEnumValue; } } +static auto __attribute__((unused)) EnsureKnownEnumValue(Globals::RelativePositionTag val) +{ + using EnumType = Globals::RelativePositionTag; + switch (val) + { + case EnumType::kUnder: + case EnumType::kNextTo: + case EnumType::kAround: + case EnumType::kOn: + case EnumType::kAbove: + case EnumType::kFrontOf: + case EnumType::kBehind: + return val; + default: + return EnumType::kUnknownEnumValue; + } +} + static auto __attribute__((unused)) EnsureKnownEnumValue(Globals::TestGlobalEnum val) { using EnumType = Globals::TestGlobalEnum; diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h index a66b926a9cacc6..a0407517696744 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h @@ -390,25 +390,35 @@ enum class LandmarkTag : uint8_t // Enum for PositionTag enum class PositionTag : uint8_t { - kLeft = 0x00, - kRight = 0x01, - kTop = 0x02, - kBottom = 0x03, - kMiddle = 0x04, - kRow = 0x05, - kColumn = 0x06, - kUnder = 0x07, - kNextTo = 0x08, - kAround = 0x09, - kOn = 0x0A, - kAbove = 0x0B, - kFrontOf = 0x0C, - kBehind = 0x0D, + kLeft = 0x00, + kRight = 0x01, + kTop = 0x02, + kBottom = 0x03, + kMiddle = 0x04, + kRow = 0x05, + kColumn = 0x06, // All received enum values that are not listed above will be mapped // to kUnknownEnumValue. This is a helper enum value that should only // be used by code to process how it handles receiving and unknown // enum value. This specific should never be transmitted. - kUnknownEnumValue = 14, + kUnknownEnumValue = 7, +}; + +// Enum for RelativePositionTag +enum class RelativePositionTag : uint8_t +{ + kUnder = 0x00, + kNextTo = 0x01, + kAround = 0x02, + kOn = 0x03, + kAbove = 0x04, + kFrontOf = 0x05, + kBehind = 0x06, + // All received enum values that are not listed above will be mapped + // to kUnknownEnumValue. This is a helper enum value that should only + // be used by code to process how it handles receiving and unknown + // enum value. This specific should never be transmitted. + kUnknownEnumValue = 7, }; // Enum for TestGlobalEnum From d9376bebcf810ce8be6d00d3ca9e845b37aebc63 Mon Sep 17 00:00:00 2001 From: Amine Alami <43780877+Alami-Amine@users.noreply.github.com> Date: Tue, 6 Aug 2024 15:08:23 +0200 Subject: [PATCH 17/41] passing c++ flags to compiler (#34777) --- build/config/compiler/BUILD.gn | 1 + 1 file changed, 1 insertion(+) diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 93333078f6f477..3de1749b37d58a 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn @@ -489,6 +489,7 @@ config("libfuzzer_fuzzing") { config("oss_fuzz") { cflags = string_split(getenv("CFLAGS")) + cflags_cc = string_split(getenv("CXXFLAGS")) ldflags = string_split(getenv("CXXFLAGS")) ldflags += [ getenv("LIB_FUZZING_ENGINE") ] } From 545b034328f48b1d15cddac851ea6e0753ac4efa Mon Sep 17 00:00:00 2001 From: wyhong <30567533+wy-hh@users.noreply.github.com> Date: Tue, 6 Aug 2024 21:09:43 +0800 Subject: [PATCH 18/41] [Bouffalo Lab] Update gcc toolchain and flash tool of docker image (#34621) * [Bouffalo Lab] Update toolchain and docker image * fix restyled * only contain changes on docker image --- .../docker/images/base/chip-build/version | 2 +- .../stage-2/chip-build-bouffalolab/Dockerfile | 11 ++- .../stage-2/chip-build-bouffalolab/setup.sh | 69 ++++++++++++------- .../vscode/chip-build-vscode/Dockerfile | 5 -- .../flashing/bouffalolab_firmware_utils.py | 0 5 files changed, 51 insertions(+), 36 deletions(-) mode change 100644 => 100755 integrations/docker/images/stage-2/chip-build-bouffalolab/setup.sh mode change 100644 => 100755 scripts/flashing/bouffalolab_firmware_utils.py diff --git a/integrations/docker/images/base/chip-build/version b/integrations/docker/images/base/chip-build/version index 9f538399a5cf06..c797fa2a19186b 100644 --- a/integrations/docker/images/base/chip-build/version +++ b/integrations/docker/images/base/chip-build/version @@ -1 +1 @@ -67 : [ESP32] Update esp-idf to v5.3 +68 : [Bouffalo Lab] Update gcc toolchain and flash tool diff --git a/integrations/docker/images/stage-2/chip-build-bouffalolab/Dockerfile b/integrations/docker/images/stage-2/chip-build-bouffalolab/Dockerfile index ad099fc48b6ef3..be286425ae905a 100644 --- a/integrations/docker/images/stage-2/chip-build-bouffalolab/Dockerfile +++ b/integrations/docker/images/stage-2/chip-build-bouffalolab/Dockerfile @@ -2,16 +2,15 @@ ARG VERSION=1 FROM ghcr.io/project-chip/chip-build:${VERSION} LABEL org.opencontainers.image.source https://github.com/project-chip/connectedhomeip -RUN apt update -y \ - && apt install vim -fy \ - && apt clean \ - && pip3 install --break-system-packages bflb-iot-tool==1.8.6 \ - && : # last line +RUN apt update + +RUN apt install picocom curl -y +RUN apt install netcat-traditional -y COPY setup.sh /tmp RUN cd /tmp \ - && bash setup.sh \ + && bash setup.sh /opt/bouffalolab_sdk \ && rm setup.sh \ && : # last line diff --git a/integrations/docker/images/stage-2/chip-build-bouffalolab/setup.sh b/integrations/docker/images/stage-2/chip-build-bouffalolab/setup.sh old mode 100644 new mode 100755 index 44e353432ccab8..1052d6c6d6774a --- a/integrations/docker/images/stage-2/chip-build-bouffalolab/setup.sh +++ b/integrations/docker/images/stage-2/chip-build-bouffalolab/setup.sh @@ -1,33 +1,40 @@ #!/usr/bin/env bash -set -x CURRENT_DIR=$( cd "$(dirname "$0")" pwd ) +user=$(stat -c %U "$0") + SDK_ROOT=/opt/bouffalolab_sdk -# Currently, only setup toolchain under $SDK_ROOT -TOOLCHAIN_SETUP_ROOT=$SDK_ROOT/toolchain -TOOLCHAIN_SYMBOLIC_LINK_PATH="" -git -C . rev-parse 2>/dev/null -if [[ "$?" == "0" ]]; then - # Examples in Bouffalo Lab IOT SDK repo expect toolchain under repo, - # let's create a symbolic link to Bouffalo Lab toolchain, - # if this script runs under repo - TOOLCHAIN_SYMBOLIC_LINK_PATH=$CURRENT_DIR/../toolchain +echo "Please input path to install toolchain, or type Enter to install under $SDK_ROOT" +read TOOLCHAIN_SETUP_ROOT +if [[ ${TOOLCHAIN_SETUP_ROOT} == "" ]]; then + TOOLCHAIN_SETUP_ROOT=$SDK_ROOT fi +echo "Toolchain will install under $TOOLCHAIN_SETUP_ROOT" +flash_tool_postfix= + +flash_tool=BouffaloLabDevCube-v1.9.0 +flash_tool_url=https://dev.bouffalolab.com/media/upload/download/$flash_tool.zip +thead_toolchain=gcc_t-head_v2.6.1 +thead_toolchain_url=https://codeload.github.com/bouffalolab/toolchain_gcc_t-head_linux/zip/c4afe91cbd01bf7dce525e0d23b4219c8691e8f0 +thead_toolchain_unzip=toolchain_gcc_t-head_linux-c4afe91cbd01bf7dce525e0d23b4219c8691e8f0 if [[ "$OSTYPE" == "linux-gnu"* ]]; then toolchains_url=( - "riscv/Thead_riscv/Linux_x86_64" "https://dev.bouffalolab.com/media/upload/download/toolchain_riscv_thead_linux64.zip" "toolchain_riscv_thead_linux_x86_64" - "riscv/Linux" "https://dev.bouffalolab.com/media/upload/download/toolchain_riscv_sifive_linux64.zip" "toolchain_riscv_sifive_linux" + "toolchain/riscv" "https://dev.bouffalolab.com/media/upload/download/toolchain_riscv_sifive_linux64.zip" Linux toolchain_riscv_sifive_linux + "toolchain/t-head-riscv" "$thead_toolchain_url" "$thead_toolchain" "$thead_toolchain_unzip" + "flashtool" "$flash_tool_url" "$flash_tool" "" ) + flash_tool_postfix=ubuntu elif [[ "$OSTYPE" == "darwin"* ]]; then toolchains_url=( - "riscv/Darwin" "https://dev.bouffalolab.com/media/upload/download/toolchain_riscv_sifive_macos.zip" "toolchain_riscv_sifive_macos" + "toolchain/riscv/Darwin" "https://dev.bouffalolab.com/media/upload/download/toolchain_riscv_sifive_macos.zip" ) + flash_tool_postfix=macos else echo "Not support for ""$OSTYPE" fi @@ -37,30 +44,44 @@ if [ ! -d "$TOOLCHAIN_SETUP_ROOT" ]; then fi rm -rf "$TOOLCHAIN_SETUP_ROOT"/*.zip -for ((i = 0; i < ${#toolchains_url[@]}; i += 3)); do +for ((i = 0; i < ${#toolchains_url[@]}; i += 4)); do path=${toolchains_url[i]} url=${toolchains_url[i + 1]} - output=${toolchains_url[i + 2]} + out=${toolchains_url[i + 2]} + unzip_name=${toolchains_url[i + 3]} + + if [ -d "$TOOLCHAIN_SETUP_ROOT/$path/$out" ]; then + continue + fi + rm -rf "$TOOLCHAIN_SETUP_ROOT/$path" + mkdir -p "$TOOLCHAIN_SETUP_ROOT/$path" wget -P "$TOOLCHAIN_SETUP_ROOT"/ "$url" toolchain_zip=$(basename "$url") + toolchain_zip=$(find "$TOOLCHAIN_SETUP_ROOT" -maxdepth 1 -name *"$toolchain_zip"*) + toolchain_zip=$(basename "$toolchain_zip") if [ ! -f "$TOOLCHAIN_SETUP_ROOT/$toolchain_zip" ]; then exit 1 fi - rm -rf "$TOOLCHAIN_SETUP_ROOT/$path" - mkdir -p "$TOOLCHAIN_SETUP_ROOT/$path" - unzip "$TOOLCHAIN_SETUP_ROOT/$toolchain_zip" -d "$TOOLCHAIN_SETUP_ROOT/$path" - mv "$TOOLCHAIN_SETUP_ROOT/$path/$output"/* "$TOOLCHAIN_SETUP_ROOT/$path" + + unzip -q "$TOOLCHAIN_SETUP_ROOT/$toolchain_zip" -d "$TOOLCHAIN_SETUP_ROOT/$path/tmp" + mv "$TOOLCHAIN_SETUP_ROOT/$path/tmp/$unzip_name" "$TOOLCHAIN_SETUP_ROOT/$path/$out" + + rm -rf "$TOOLCHAIN_SETUP_ROOT/$path"/tmp rm -rf "$TOOLCHAIN_SETUP_ROOT/$toolchain_zip" - if [ -f "$TOOLCHAIN_SETUP_ROOT/$path"/chmod755.sh ]; then - cd "$TOOLCHAIN_SETUP_ROOT/$path"/ + if [ -f "$TOOLCHAIN_SETUP_ROOT/$path"/"$out"/chmod755.sh ]; then + cd "$TOOLCHAIN_SETUP_ROOT/$path"/"$out" bash chmod755.sh cd "$CURRENT_DIR" fi done -if [[ "$TOOLCHAIN_SYMBOLIC_LINK_PATH" != "" ]]; then - rm -rf "$TOOLCHAIN_SYMBOLIC_LINK_PATH" - ln -s "$TOOLCHAIN_SETUP_ROOT" "$TOOLCHAIN_SYMBOLIC_LINK_PATH" +chmod +x "$TOOLCHAIN_SETUP_ROOT/flashtool/$flash_tool/BLDevCube-$flash_tool_postfix" +chmod +x "$TOOLCHAIN_SETUP_ROOT/flashtool/$flash_tool/bflb_iot_tool-$flash_tool_postfix" + +if [[ "$user" == "root" ]]; then + chmod a+wr "$TOOLCHAIN_SETUP_ROOT/flashtool/$flash_tool" -R +else + chown "$user" "$TOOLCHAIN_SETUP_ROOT/flashtool/$flash_tool"/ -R fi diff --git a/integrations/docker/images/vscode/chip-build-vscode/Dockerfile b/integrations/docker/images/vscode/chip-build-vscode/Dockerfile index df6018847acb59..6bde4b8cb8431f 100644 --- a/integrations/docker/images/vscode/chip-build-vscode/Dockerfile +++ b/integrations/docker/images/vscode/chip-build-vscode/Dockerfile @@ -107,11 +107,6 @@ RUN set -x \ && rm -rf /var/lib/apt/lists/ \ && : # last line -# Required for the Bouffalolab platform -RUN set -x \ - && pip3 install --break-system-packages bflb-iot-tool==1.8.6 \ - && : # last line - ENV PATH $PATH:/usr/lib/kotlinc/bin ENV AMEBA_PATH=/opt/ameba/ambd_sdk_with_chip_non_NDA ENV ANDROID_HOME=/opt/android/sdk diff --git a/scripts/flashing/bouffalolab_firmware_utils.py b/scripts/flashing/bouffalolab_firmware_utils.py old mode 100644 new mode 100755 From 7d9a332edaab60c1d9dcb37d8fdc4f2bcd3f7938 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Tue, 6 Aug 2024 09:43:45 -0400 Subject: [PATCH 19/41] Rename to BridgedDevice and BridgedDeviceManager (#34776) * Rename to BridgedDevice and BridgedDeviceManager * Restyled by clang-format * Restyled by gn --------- Co-authored-by: Restyled.io --- .../fabric-bridge-common/BUILD.gn | 8 ++--- .../include/{Device.h => BridgedDevice.h} | 6 ++-- ...DeviceManager.h => BridgedDeviceManager.h} | 36 +++++++++---------- .../src/{Device.cpp => BridgedDevice.cpp} | 16 ++++----- ...ceManager.cpp => BridgedDeviceManager.cpp} | 16 ++++----- .../fabric-bridge-common/src/ZCLCallbacks.cpp | 6 ++-- .../fabric-bridge-app/linux/RpcServer.cpp | 10 +++--- examples/fabric-bridge-app/linux/main.cpp | 8 ++--- 8 files changed, 53 insertions(+), 53 deletions(-) rename examples/fabric-bridge-app/fabric-bridge-common/include/{Device.h => BridgedDevice.h} (95%) rename examples/fabric-bridge-app/fabric-bridge-common/include/{DeviceManager.h => BridgedDeviceManager.h} (76%) rename examples/fabric-bridge-app/fabric-bridge-common/src/{Device.cpp => BridgedDevice.cpp} (70%) rename examples/fabric-bridge-app/fabric-bridge-common/src/{DeviceManager.cpp => BridgedDeviceManager.cpp} (95%) diff --git a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn index 3bc4c23b9e0f92..10cb48c31c584e 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn +++ b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn @@ -29,11 +29,11 @@ source_set("fabric-bridge-lib") { public_configs = [ ":config" ] sources = [ + "include/BridgedDevice.h", + "include/BridgedDeviceManager.h", "include/CHIPProjectAppConfig.h", - "include/Device.h", - "include/DeviceManager.h", - "src/Device.cpp", - "src/DeviceManager.cpp", + "src/BridgedDevice.cpp", + "src/BridgedDeviceManager.cpp", "src/ZCLCallbacks.cpp", ] diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/Device.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h similarity index 95% rename from examples/fabric-bridge-app/fabric-bridge-common/include/Device.h rename to examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h index c709af8cf0695b..a237d93d133eb7 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/include/Device.h +++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h @@ -27,13 +27,13 @@ #include #include -class Device +class BridgedDevice { public: static const int kDeviceNameSize = 32; - Device(chip::NodeId nodeId); - virtual ~Device() {} + BridgedDevice(chip::NodeId nodeId); + virtual ~BridgedDevice() {} bool IsReachable(); void SetReachable(bool reachable); diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/DeviceManager.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h similarity index 76% rename from examples/fabric-bridge-app/fabric-bridge-common/include/DeviceManager.h rename to examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h index b1dd791033511f..8411ec656f9803 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/include/DeviceManager.h +++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h @@ -20,17 +20,17 @@ #include -#include "Device.h" +#include "BridgedDevice.h" -class DeviceManager +class BridgedDeviceManager { public: - DeviceManager() = default; + BridgedDeviceManager() = default; /** - * @brief Initializes the DeviceManager. + * @brief Initializes the BridgedDeviceManager. * - * This function sets up the initial state of the DeviceManager, clearing + * This function sets up the initial state of the BridgedDeviceManager, clearing * any existing devices and setting the starting dynamic endpoint ID. */ void Init(); @@ -47,7 +47,7 @@ class DeviceManager * @param parentEndpointId The parent endpoint ID. Defaults to an invalid endpoint ID. * @return int The index of the dynamic endpoint if successful, -1 otherwise. */ - int AddDeviceEndpoint(Device * dev, chip::EndpointId parentEndpointId = chip::kInvalidEndpointId); + int AddDeviceEndpoint(BridgedDevice * dev, chip::EndpointId parentEndpointId = chip::kInvalidEndpointId); /** * @brief Removes a device from a dynamic endpoint. @@ -60,7 +60,7 @@ class DeviceManager * @param dev A pointer to the device to be removed. * @return int The index of the removed dynamic endpoint if successful, -1 otherwise. */ - int RemoveDeviceEndpoint(Device * dev); + int RemoveDeviceEndpoint(BridgedDevice * dev); /** * @brief Gets a device from its endpoint ID. @@ -69,9 +69,9 @@ class DeviceManager * specified endpoint ID. If no device matches the endpoint ID, it returns nullptr. * * @param endpointId The endpoint ID of the device to be retrieved. - * @return Device* A pointer to the device if found, nullptr otherwise. + * @return BridgedDevice* A pointer to the device if found, nullptr otherwise. */ - Device * GetDevice(chip::EndpointId endpointId) const; + BridgedDevice * GetDevice(chip::EndpointId endpointId) const; /** * @brief Gets a device from its NodeId. @@ -80,9 +80,9 @@ class DeviceManager * specified NodeId. If no device matches the NodeId, it returns nullptr. * * @param nodeId The NodeId of the device to be retrieved. - * @return Device* A pointer to the device if found, nullptr otherwise. + * @return BridgedDevice* A pointer to the device if found, nullptr otherwise. */ - Device * GetDeviceByNodeId(chip::NodeId nodeId) const; + BridgedDevice * GetDeviceByNodeId(chip::NodeId nodeId) const; /** * @brief Removes a device from a dynamic endpoint by its NodeId. @@ -98,22 +98,22 @@ class DeviceManager int RemoveDeviceByNodeId(chip::NodeId nodeId); private: - friend DeviceManager & DeviceMgr(); + friend BridgedDeviceManager & BridgeDeviceMgr(); - static DeviceManager sInstance; + static BridgedDeviceManager sInstance; chip::EndpointId mCurrentEndpointId; chip::EndpointId mFirstDynamicEndpointId; - Device * mDevices[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT + 1]; + BridgedDevice * mDevices[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT + 1]; }; /** - * Returns the public interface of the DeviceManager singleton object. + * Returns the public interface of the BridgedDeviceManager singleton object. * - * Applications should use this to access features of the DeviceManager + * Applications should use this to access features of the BridgedDeviceManager * object. */ -inline DeviceManager & DeviceMgr() +inline BridgedDeviceManager & BridgeDeviceMgr() { - return DeviceManager::sInstance; + return BridgedDeviceManager::sInstance; } diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/Device.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp similarity index 70% rename from examples/fabric-bridge-app/fabric-bridge-common/src/Device.cpp rename to examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp index e72fd856513b5a..d641f3743d43f0 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/src/Device.cpp +++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp @@ -16,7 +16,7 @@ * limitations under the License. */ -#include "Device.h" +#include "BridgedDevice.h" #include #include @@ -25,35 +25,35 @@ using namespace chip::app::Clusters::Actions; -Device::Device(chip::NodeId nodeId) +BridgedDevice::BridgedDevice(chip::NodeId nodeId) { mReachable = false; mNodeId = nodeId; mEndpointId = chip::kInvalidEndpointId; } -bool Device::IsReachable() +bool BridgedDevice::IsReachable() { return mReachable; } -void Device::SetReachable(bool reachable) +void BridgedDevice::SetReachable(bool reachable) { mReachable = reachable; if (reachable) { - ChipLogProgress(NotSpecified, "Device[%s]: ONLINE", mName); + ChipLogProgress(NotSpecified, "BridgedDevice[%s]: ONLINE", mName); } else { - ChipLogProgress(NotSpecified, "Device[%s]: OFFLINE", mName); + ChipLogProgress(NotSpecified, "BridgedDevice[%s]: OFFLINE", mName); } } -void Device::SetName(const char * name) +void BridgedDevice::SetName(const char * name) { - ChipLogProgress(NotSpecified, "Device[%s]: New Name=\"%s\"", mName, name); + ChipLogProgress(NotSpecified, "BridgedDevice[%s]: New Name=\"%s\"", mName, name); chip::Platform::CopyString(mName, name); } diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/DeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp similarity index 95% rename from examples/fabric-bridge-app/fabric-bridge-common/src/DeviceManager.cpp rename to examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp index bc70c0cb0fe609..170b39cd2c94e2 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/src/DeviceManager.cpp +++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp @@ -16,7 +16,7 @@ * limitations under the License. */ -#include "DeviceManager.h" +#include "BridgedDeviceManager.h" #include #include @@ -121,9 +121,9 @@ const EmberAfDeviceType sBridgedDeviceTypes[] = { { DEVICE_TYPE_BRIDGED_NODE, DE } // namespace // Define the static member -DeviceManager DeviceManager::sInstance; +BridgedDeviceManager BridgedDeviceManager::sInstance; -void DeviceManager::Init() +void BridgedDeviceManager::Init() { memset(mDevices, 0, sizeof(mDevices)); mFirstDynamicEndpointId = static_cast( @@ -131,7 +131,7 @@ void DeviceManager::Init() mCurrentEndpointId = mFirstDynamicEndpointId; } -int DeviceManager::AddDeviceEndpoint(Device * dev, chip::EndpointId parentEndpointId) +int BridgedDeviceManager::AddDeviceEndpoint(BridgedDevice * dev, chip::EndpointId parentEndpointId) { uint8_t index = 0; EmberAfEndpointType * ep = &sBridgedNodeEndpoint; @@ -181,7 +181,7 @@ int DeviceManager::AddDeviceEndpoint(Device * dev, chip::EndpointId parentEndpoi return -1; } -int DeviceManager::RemoveDeviceEndpoint(Device * dev) +int BridgedDeviceManager::RemoveDeviceEndpoint(BridgedDevice * dev) { uint8_t index = 0; while (index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT) @@ -201,7 +201,7 @@ int DeviceManager::RemoveDeviceEndpoint(Device * dev) return -1; } -Device * DeviceManager::GetDevice(chip::EndpointId endpointId) const +BridgedDevice * BridgedDeviceManager::GetDevice(chip::EndpointId endpointId) const { for (uint8_t index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; ++index) { @@ -213,7 +213,7 @@ Device * DeviceManager::GetDevice(chip::EndpointId endpointId) const return nullptr; } -Device * DeviceManager::GetDeviceByNodeId(chip::NodeId nodeId) const +BridgedDevice * BridgedDeviceManager::GetDeviceByNodeId(chip::NodeId nodeId) const { for (uint8_t index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; ++index) { @@ -225,7 +225,7 @@ Device * DeviceManager::GetDeviceByNodeId(chip::NodeId nodeId) const return nullptr; } -int DeviceManager::RemoveDeviceByNodeId(chip::NodeId nodeId) +int BridgedDeviceManager::RemoveDeviceByNodeId(chip::NodeId nodeId) { for (uint8_t index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; ++index) { diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp index 1655df4c2f1399..9a0467be4e27e8 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp +++ b/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp @@ -15,7 +15,7 @@ * limitations under the License. */ -#include "DeviceManager.h" +#include "BridgedDeviceManager.h" #include #include @@ -36,7 +36,7 @@ Protocols::InteractionModel::Status emberAfExternalAttributeReadCallback(Endpoin { AttributeId attributeId = attributeMetadata->attributeId; - Device * dev = DeviceMgr().GetDevice(endpoint); + BridgedDevice * dev = BridgeDeviceMgr().GetDevice(endpoint); if (dev != nullptr && clusterId == app::Clusters::BridgedDeviceBasicInformation::Id) { using namespace app::Clusters::BridgedDeviceBasicInformation::Attributes; @@ -80,7 +80,7 @@ Protocols::InteractionModel::Status emberAfExternalAttributeWriteCallback(Endpoi uint16_t endpointIndex = emberAfGetDynamicIndexFromEndpoint(endpoint); Protocols::InteractionModel::Status ret = Protocols::InteractionModel::Status::Failure; - Device * dev = DeviceMgr().GetDevice(endpointIndex); + BridgedDevice * dev = BridgeDeviceMgr().GetDevice(endpointIndex); if (dev != nullptr && dev->IsReachable()) { ChipLogProgress(NotSpecified, "emberAfExternalAttributeWriteCallback: ep=%d, clusterId=%d", endpoint, clusterId); diff --git a/examples/fabric-bridge-app/linux/RpcServer.cpp b/examples/fabric-bridge-app/linux/RpcServer.cpp index d4044f043468d3..76fe8f84653d39 100644 --- a/examples/fabric-bridge-app/linux/RpcServer.cpp +++ b/examples/fabric-bridge-app/linux/RpcServer.cpp @@ -29,8 +29,8 @@ #include "pigweed/rpc_services/FabricBridge.h" #endif -#include "Device.h" -#include "DeviceManager.h" +#include "BridgedDevice.h" +#include "BridgedDeviceManager.h" using namespace chip; using namespace chip::app; @@ -51,10 +51,10 @@ pw::Status FabricBridge::AddSynchronizedDevice(const chip_rpc_SynchronizedDevice NodeId nodeId = request.node_id; ChipLogProgress(NotSpecified, "Received AddSynchronizedDevice: " ChipLogFormatX64, ChipLogValueX64(nodeId)); - Device * device = new Device(nodeId); + BridgedDevice * device = new BridgedDevice(nodeId); device->SetReachable(true); - int result = DeviceMgr().AddDeviceEndpoint(device, 1); + int result = BridgeDeviceMgr().AddDeviceEndpoint(device, 1); if (result == -1) { delete device; @@ -70,7 +70,7 @@ pw::Status FabricBridge::RemoveSynchronizedDevice(const chip_rpc_SynchronizedDev NodeId nodeId = request.node_id; ChipLogProgress(NotSpecified, "Received RemoveSynchronizedDevice: " ChipLogFormatX64, ChipLogValueX64(nodeId)); - int removed_idx = DeviceMgr().RemoveDeviceByNodeId(nodeId); + int removed_idx = BridgeDeviceMgr().RemoveDeviceByNodeId(nodeId); if (removed_idx < 0) { ChipLogError(NotSpecified, "Failed to remove device with nodeId=0x" ChipLogFormatX64, ChipLogValueX64(nodeId)); diff --git a/examples/fabric-bridge-app/linux/main.cpp b/examples/fabric-bridge-app/linux/main.cpp index d8fb45dea08a02..c708b256727520 100644 --- a/examples/fabric-bridge-app/linux/main.cpp +++ b/examples/fabric-bridge-app/linux/main.cpp @@ -18,9 +18,9 @@ #include +#include "BridgedDevice.h" +#include "BridgedDeviceManager.h" #include "CommissionableInit.h" -#include "Device.h" -#include "DeviceManager.h" #include #include @@ -140,7 +140,7 @@ void AdministratorCommissioningCommandHandler::InvokeCommand(HandlerContext & ha Status status = Status::Failure; #if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE - Device * device = DeviceMgr().GetDevice(endpointId); + BridgedDevice * device = BridgeDeviceMgr().GetDevice(endpointId); // TODO: issues:#33784, need to make OpenCommissioningWindow synchronous if (device != nullptr && @@ -185,7 +185,7 @@ void ApplicationInit() std::thread pollingThread(BridgePollingThread); pollingThread.detach(); - DeviceMgr().Init(); + BridgeDeviceMgr().Init(); } void ApplicationShutdown() From 4031ccb61966af608049fd4c45daa6dd918bfe15 Mon Sep 17 00:00:00 2001 From: Nivi Sarkar <55898241+nivi-apple@users.noreply.github.com> Date: Tue, 6 Aug 2024 08:28:57 -0700 Subject: [PATCH 20/41] =?UTF-8?q?Fix=20the=20CountUpdatedPresetsAfterApply?= =?UTF-8?q?ingPendingPresets=20utility=20functi=E2=80=A6=20(#34780)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix the CountUpdatedPresetsAfterApplyingPendingPresets utility function to return the size of the pending presets list * Restyled by clang-format * Remove unnecessary cast for numberOfPendingPresets * Update thermostat-server.cpp * Restyled by clang-format --------- Co-authored-by: Restyled.io --- .../thermostat-server/thermostat-server.cpp | 43 ++++--------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/src/app/clusters/thermostat-server/thermostat-server.cpp b/src/app/clusters/thermostat-server/thermostat-server.cpp index afdb1b12afe763..fb60b046183b28 100644 --- a/src/app/clusters/thermostat-server/thermostat-server.cpp +++ b/src/app/clusters/thermostat-server/thermostat-server.cpp @@ -321,46 +321,21 @@ bool IsPresetHandlePresentInPresets(Delegate * delegate, const ByteSpan & preset } /** - * @brief Returns the length of the list of presets if the pending presets were to be applied. The calculation is done by - * adding the number of presets in Presets attribute list to the number of pending presets in the pending - * presets list and subtracting the number of duplicate presets. This is called before changes are actually applied. + * @brief Returns the length of the list of presets if the pending presets were to be applied. The size of the pending presets list + * calculated, after all the constraint checks are done, is the new size of the updated Presets attribute since the pending + * preset list is expected to have all existing presets with or without edits plus new presets. + * This is called before changes are actually applied. * * @param[in] delegate The delegate to use. * * @return count of the updated Presets attribute if the pending presets were applied to it. Return 0 for error cases. */ -uint8_t CountUpdatedPresetsAfterApplyingPendingPresets(Delegate * delegate) +uint8_t CountNumberOfPendingPresets(Delegate * delegate) { - uint8_t numberOfPresets = 0; - uint8_t numberOfMatches = 0; uint8_t numberOfPendingPresets = 0; VerifyOrReturnValue(delegate != nullptr, 0); - for (uint8_t i = 0; true; i++) - { - PresetStructWithOwnedMembers preset; - CHIP_ERROR err = delegate->GetPresetAtIndex(i, preset); - - if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) - { - break; - } - if (err != CHIP_NO_ERROR) - { - ChipLogError(Zcl, "GetUpdatedPresetsCount: GetPresetAtIndex failed with error %" CHIP_ERROR_FORMAT, err.Format()); - return 0; - } - numberOfPresets++; - - bool found = MatchingPendingPresetExists(delegate, preset); - - if (found) - { - numberOfMatches++; - } - } - for (uint8_t i = 0; true; i++) { PresetStructWithOwnedMembers pendingPreset; @@ -372,16 +347,14 @@ uint8_t CountUpdatedPresetsAfterApplyingPendingPresets(Delegate * delegate) } if (err != CHIP_NO_ERROR) { - ChipLogError(Zcl, "GetUpdatedPresetsCount: GetPendingPresetAtIndex failed with error %" CHIP_ERROR_FORMAT, + ChipLogError(Zcl, "CountNumberOfPendingPresets: GetPendingPresetAtIndex failed with error %" CHIP_ERROR_FORMAT, err.Format()); return 0; } numberOfPendingPresets++; } - // TODO: #34546 - Need to support deletion of presets that are removed from Presets. - // This API needs to modify its logic for the deletion case. - return static_cast(numberOfPresets + numberOfPendingPresets - numberOfMatches); + return numberOfPendingPresets; } /** @@ -1538,7 +1511,7 @@ imcode commitPresets(Delegate * delegate, EndpointId endpoint) } } - uint8_t totalCount = CountUpdatedPresetsAfterApplyingPendingPresets(delegate); + uint8_t totalCount = CountNumberOfPendingPresets(delegate); uint8_t numberOfPresetsSupported = delegate->GetNumberOfPresets(); From 7ee93d2bd4519859bd773ff66b92695d6aece317 Mon Sep 17 00:00:00 2001 From: jamesharrow <93921463+jamesharrow@users.noreply.github.com> Date: Tue, 6 Aug 2024 16:33:48 +0100 Subject: [PATCH 21/41] Fixes #34576 - Added missing step 22 that was in the test plan, but missing in the test script. (#34779) --- src/python_testing/TC_EEVSE_2_3.py | 6 ++++++ src/python_testing/TC_EEVSE_Utils.py | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/python_testing/TC_EEVSE_2_3.py b/src/python_testing/TC_EEVSE_2_3.py index d8d8f8fdfb96b5..9ff68eec659c0d 100644 --- a/src/python_testing/TC_EEVSE_2_3.py +++ b/src/python_testing/TC_EEVSE_2_3.py @@ -134,6 +134,9 @@ def steps_TC_EEVSE_2_3(self) -> list[TestStep]: "Verify Command response is Success and event EEVSE.S.E01(EVNotDetected) sent"), TestStep("21", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EEVSE.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EEVSE.TEST_EVENT_TRIGGER for Basic Functionality Test Event Clear.", "Verify Command response is Success"), + TestStep("22", "TH sends TestEventTrigger command to General Diagnostics Cluster on Endpoint 0 with EnableKey field set to PIXIT.EEVSE.TEST_EVENT_TRIGGER_KEY and EventTrigger field set to PIXIT.EEVSE.TEST_EVENT_TRIGGER for for EVSE TimeOfUse Mode Test Event Clear.", + "Verify Command response is Success"), + ] return steps @@ -449,6 +452,9 @@ async def test_TC_EEVSE_2_3(self): self.step("21") await self.send_test_event_trigger_basic_clear() + self.step("22") + await self.send_test_event_trigger_time_of_use_mode_clear() + if __name__ == "__main__": default_matter_test_main() diff --git a/src/python_testing/TC_EEVSE_Utils.py b/src/python_testing/TC_EEVSE_Utils.py index 17f64191ed37ec..244d2e5730f28d 100644 --- a/src/python_testing/TC_EEVSE_Utils.py +++ b/src/python_testing/TC_EEVSE_Utils.py @@ -160,6 +160,9 @@ async def send_test_event_trigger_charge_demand_clear(self): async def send_test_event_trigger_time_of_use_mode(self): await self.send_test_event_triggers(eventTrigger=0x0099000000000006) + async def send_test_event_trigger_time_of_use_mode_clear(self): + await self.send_test_event_triggers(eventTrigger=0x0099000000000021) + async def send_test_event_trigger_evse_ground_fault(self): await self.send_test_event_triggers(eventTrigger=0x0099000000000010) From c06221bcac5793ddb1fd3bb21c8fb948bb4ad52c Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Tue, 6 Aug 2024 13:14:59 -0400 Subject: [PATCH 22/41] Fix ecosystem information cluster when reading cluster revision (#34792) * Fix ecosystem information cluster when reading cluster revision * Restyled by clang-format --------- Co-authored-by: Restyled.io --- .../ecosystem-information-server.cpp | 40 +++++++++++++------ .../ecosystem-information-server.h | 9 +++-- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp index 4d7f7b8ddf754e..74a27f21779ff9 100644 --- a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp +++ b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp @@ -26,6 +26,9 @@ namespace Clusters { namespace EcosystemInformation { namespace { +#define ZCL_ECOSYSTEM_INFORMATION_CLUSTER_REVISION (1u) +#define ZCL_ECOSYSTEM_INFORMATION_FEATURE_MAP (0u) + constexpr size_t kDeviceNameMaxSize = 64; constexpr size_t kUniqueLocationIdMaxSize = 64; constexpr size_t kUniqueLocationIdsListMaxSize = 64; @@ -46,18 +49,7 @@ class AttrAccess : public AttributeAccessInterface CHIP_ERROR AttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) { VerifyOrDie(aPath.mClusterId == Clusters::EcosystemInformation::Id); - switch (aPath.mAttributeId) - { - case Attributes::RemovedOn::Id: - return EcosystemInformationServer::Instance().EncodeRemovedOnAttribute(aPath.mEndpointId, aEncoder); - case Attributes::DeviceDirectory ::Id: - return EcosystemInformationServer::Instance().EncodeDeviceDirectoryAttribute(aPath.mEndpointId, aEncoder); - case Attributes::LocationDirectory ::Id: - return EcosystemInformationServer::Instance().EncodeLocationStructAttribute(aPath.mEndpointId, aEncoder); - default: - break; - } - return CHIP_NO_ERROR; + return EcosystemInformationServer::Instance().ReadAttribute(aPath, aEncoder); } // WARNING: caller is expected to use the returned LocationDescriptorStruct::Type immediately. Caller must @@ -285,6 +277,30 @@ CHIP_ERROR EcosystemInformationServer::RemoveDevice(EndpointId aEndpoint, uint64 return CHIP_NO_ERROR; } +CHIP_ERROR EcosystemInformationServer::ReadAttribute(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + switch (aPath.mAttributeId) + { + case Attributes::RemovedOn::Id: + return EcosystemInformationServer::Instance().EncodeRemovedOnAttribute(aPath.mEndpointId, aEncoder); + case Attributes::DeviceDirectory::Id: + return EcosystemInformationServer::Instance().EncodeDeviceDirectoryAttribute(aPath.mEndpointId, aEncoder); + case Attributes::LocationDirectory::Id: + return EcosystemInformationServer::Instance().EncodeLocationStructAttribute(aPath.mEndpointId, aEncoder); + case Attributes::ClusterRevision::Id: { + uint16_t rev = ZCL_ECOSYSTEM_INFORMATION_CLUSTER_REVISION; + return aEncoder.Encode(rev); + } + case Attributes::FeatureMap::Id: { + uint32_t featureMap = ZCL_ECOSYSTEM_INFORMATION_FEATURE_MAP; + return aEncoder.Encode(featureMap); + } + default: + break; + } + return CHIP_NO_ERROR; +} + CHIP_ERROR EcosystemInformationServer::EncodeRemovedOnAttribute(EndpointId aEndpoint, AttributeValueEncoder & aEncoder) { auto it = mDevicesMap.find(aEndpoint); diff --git a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h index 58c64262166403..daa6f0124d9e39 100644 --- a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h +++ b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h @@ -182,9 +182,7 @@ class EcosystemInformationServer CHIP_ERROR RemoveDevice(EndpointId aEndpoint, uint64_t aEpochUs); // TODO(#33223) Add removal and update counterparts to AddDeviceInfo and AddLocationInfo. - CHIP_ERROR EncodeRemovedOnAttribute(EndpointId aEndpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR EncodeDeviceDirectoryAttribute(EndpointId aEndpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR EncodeLocationStructAttribute(EndpointId aEndpoint, AttributeValueEncoder & aEncoder); + CHIP_ERROR ReadAttribute(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder); private: struct DeviceInfo @@ -194,6 +192,11 @@ class EcosystemInformationServer // Map key is using the UniqueLocationId std::map> mLocationDirectory; }; + + CHIP_ERROR EncodeRemovedOnAttribute(EndpointId aEndpoint, AttributeValueEncoder & aEncoder); + CHIP_ERROR EncodeDeviceDirectoryAttribute(EndpointId aEndpoint, AttributeValueEncoder & aEncoder); + CHIP_ERROR EncodeLocationStructAttribute(EndpointId aEndpoint, AttributeValueEncoder & aEncoder); + std::map mDevicesMap; static EcosystemInformationServer mInstance; From e58e16e1e42646a8b151f0638214269c867e1e87 Mon Sep 17 00:00:00 2001 From: William Date: Tue, 6 Aug 2024 18:23:58 +0100 Subject: [PATCH 23/41] Service Area: Remove nullable qualities to match the latest spec (#34732) * Updated the golabl data type's XMLs, removing the cluster entries. * Zap generated after XML update. * Fixed namespaces used of global structs. * Restyled by clang-format * Renamed LocationInfoStruct to AreaInfoStruct. * Zap generated after XML update. * Renamed LocationStruct to AreaStruct and its LocationID and LocationDesc fields. * Zap generated after XML update. * Updated SDK and example code to match the new naming. * Updated the ProgressStruct's LocationID name to AreaID. * Zap generated after XML update. * Updated the SDK code following name changes. * Updated the SelectLocationsStatus and SkipLocationStatus enum names and some of their enums. * Zap generated after XML update. * Updated the SelectLocationsStatus and SkipCurrentLocationStatus names and their enum names. * Updated the names of the SupportedLocations, SelectedLocations and CurrentLocation attributes. * Zap generated after XML update. * Updated the changed names in the SDK. * Updated the service area command names in XML. * Zap generated after XML update. * Updated the service area command names in the SDK. * Updated the rvc-example zap file. * Refactored LocationStructureWrapper to AreaStructureWrapper. * Restyled by clang-format * Regenerated zap files due to changes upsteram. * Removed unused generated file. * Updated the Service Area XML marking previously nullabel attributes as not-nullable. * Zap generated after XML update. * Updated the attribute encoding and some server logic following the romoval of the nullable quality for some attributes. * spacing changes form zap regen. * Fixed minor mistake during merge. --------- Co-authored-by: Restyled.io --- examples/rvc-app/rvc-common/rvc-app.matter | 8 +- .../service-area-server.cpp | 21 +- .../data-model/chip/service-area-cluster.xml | 8 +- .../data_model/controller-clusters.matter | 8 +- .../chip/devicecontroller/ChipClusters.java | 24 +- .../devicecontroller/ClusterInfoMapping.java | 6 +- .../cluster/clusters/ServiceAreaCluster.kt | 126 +++----- .../CHIPAttributeTLVValueDecoder.cpp | 275 ++++++++---------- .../python/chip/clusters/Objects.py | 28 +- .../MTRAttributeTLVValueDecoder.mm | 140 ++++----- .../zap-generated/MTRCommandPayloadsObjc.h | 2 +- .../zap-generated/MTRCommandPayloadsObjc.mm | 41 ++- .../zap-generated/cluster-objects.h | 31 +- .../zap-generated/cluster/Commands.h | 12 +- .../cluster/logging/DataModelLogger.cpp | 10 +- .../zap-generated/cluster/Commands.h | 20 +- 16 files changed, 337 insertions(+), 423 deletions(-) diff --git a/examples/rvc-app/rvc-common/rvc-app.matter b/examples/rvc-app/rvc-common/rvc-app.matter index 596fde4138576a..7a87e9e83dbe90 100644 --- a/examples/rvc-app/rvc-common/rvc-app.matter +++ b/examples/rvc-app/rvc-common/rvc-app.matter @@ -1480,11 +1480,11 @@ provisional cluster ServiceArea = 336 { } readonly attribute AreaStruct supportedAreas[] = 0; - readonly attribute nullable MapStruct supportedMaps[] = 1; - readonly attribute nullable int32u selectedAreas[] = 2; + readonly attribute MapStruct supportedMaps[] = 1; + readonly attribute int32u selectedAreas[] = 2; readonly attribute optional nullable int32u currentArea = 3; readonly attribute optional nullable epoch_s estimatedEndTime = 4; - readonly attribute optional nullable ProgressStruct progress[] = 5; + readonly attribute optional ProgressStruct progress[] = 5; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -1493,7 +1493,7 @@ provisional cluster ServiceArea = 336 { readonly attribute int16u clusterRevision = 65533; request struct SelectAreasRequest { - nullable int32u newAreas[] = 0; + int32u newAreas[] = 0; } response struct SelectAreasResponse = 1 { diff --git a/src/app/clusters/service-area-server/service-area-server.cpp b/src/app/clusters/service-area-server/service-area-server.cpp index 66556acd03ea0b..fa5d626a5ab06c 100644 --- a/src/app/clusters/service-area-server/service-area-server.cpp +++ b/src/app/clusters/service-area-server/service-area-server.cpp @@ -134,7 +134,7 @@ CHIP_ERROR Instance::ReadSupportedAreas(AttributeValueEncoder & aEncoder) { if (mDelegate->GetNumberOfSupportedAreas() == 0) { - return aEncoder.EncodeNull(); + return aEncoder.EncodeEmptyList(); } return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { @@ -153,7 +153,7 @@ CHIP_ERROR Instance::ReadSupportedMaps(AttributeValueEncoder & aEncoder) { if (mDelegate->GetNumberOfSupportedMaps() == 0) { - return aEncoder.EncodeNull(); + return aEncoder.EncodeEmptyList(); } return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { @@ -172,7 +172,7 @@ CHIP_ERROR Instance::ReadSelectedAreas(AttributeValueEncoder & aEncoder) { if (mDelegate->GetNumberOfSelectedAreas() == 0) { - return aEncoder.EncodeNull(); + return aEncoder.EncodeEmptyList(); } return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { @@ -191,7 +191,7 @@ CHIP_ERROR Instance::ReadProgress(AttributeValueEncoder & aEncoder) { if (mDelegate->GetNumberOfProgressElements() == 0) { - return aEncoder.EncodeNull(); + return aEncoder.EncodeEmptyList(); } return aEncoder.EncodeList([this](const auto & encoder) -> CHIP_ERROR { @@ -224,9 +224,8 @@ void Instance::HandleSelectAreasCmd(HandlerContext & ctx, const Commands::Select size_t numberOfLocations = 0; // Get the number of Selected Locations in the command parameter and check that it is valid. - if (!req.newAreas.IsNull()) { - if (CHIP_NO_ERROR != req.newAreas.Value().ComputeSize(&numberOfLocations)) + if (CHIP_NO_ERROR != req.newAreas.ComputeSize(&numberOfLocations)) { ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::InvalidCommand); return; @@ -244,14 +243,14 @@ void Instance::HandleSelectAreasCmd(HandlerContext & ctx, const Commands::Select // if number of selected locations in parameter matches number in attribute - the locations *might* be the same bool matchesCurrentSelectedAreas = (numberOfLocations == mDelegate->GetNumberOfSelectedAreas()); - if (!req.newAreas.IsNull()) + if (numberOfLocations != 0) { // do as much parameter validation as we can { uint32_t ignoredIndex = 0; uint32_t oldSelectedLocation; uint32_t i = 0; - auto iLocationIter = req.newAreas.Value().begin(); + auto iLocationIter = req.newAreas.begin(); while (iLocationIter.Next()) { uint32_t aSelectedLocation = iLocationIter.GetValue(); @@ -266,7 +265,7 @@ void Instance::HandleSelectAreasCmd(HandlerContext & ctx, const Commands::Select // Checking for duplicate locations. uint32_t j = 0; - auto jLocationIter = req.newAreas.Value().begin(); + auto jLocationIter = req.newAreas.begin(); while (j < i) { jLocationIter @@ -343,9 +342,9 @@ void Instance::HandleSelectAreasCmd(HandlerContext & ctx, const Commands::Select // and the SelectedAreas attribute SHALL be set to the value of the newAreas field. mDelegate->ClearSelectedAreas(); - if (!req.newAreas.IsNull()) + if (numberOfLocations != 0) { - auto locationIter = req.newAreas.Value().begin(); + auto locationIter = req.newAreas.begin(); uint32_t ignored; while (locationIter.Next()) { diff --git a/src/app/zap-templates/zcl/data-model/chip/service-area-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/service-area-cluster.xml index f78e8966a11b94..e7b190456a2ef8 100644 --- a/src/app/zap-templates/zcl/data-model/chip/service-area-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/service-area-cluster.xml @@ -89,18 +89,18 @@ limitations under the License. SupportedAreas - SupportedMaps - SelectedAreas + SupportedMaps + SelectedAreas CurrentArea EstimatedEndTime - Progress + Progress Command used to select a set of device areas, where the device is to operate. - + diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 589f832c0ca39b..810f82819c1a19 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -6502,11 +6502,11 @@ provisional cluster ServiceArea = 336 { } readonly attribute AreaStruct supportedAreas[] = 0; - readonly attribute nullable MapStruct supportedMaps[] = 1; - readonly attribute nullable int32u selectedAreas[] = 2; + readonly attribute MapStruct supportedMaps[] = 1; + readonly attribute int32u selectedAreas[] = 2; readonly attribute optional nullable int32u currentArea = 3; readonly attribute optional nullable epoch_s estimatedEndTime = 4; - readonly attribute optional nullable ProgressStruct progress[] = 5; + readonly attribute optional ProgressStruct progress[] = 5; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute event_id eventList[] = 65530; @@ -6515,7 +6515,7 @@ provisional cluster ServiceArea = 336 { readonly attribute int16u clusterRevision = 65533; request struct SelectAreasRequest { - nullable int32u newAreas[] = 0; + int32u newAreas[] = 0; } response struct SelectAreasResponse = 1 { diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index c6a65ba56a6ae6..10863976c661a8 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -39073,16 +39073,16 @@ public long initWithDevice(long devicePtr, int endpointId) { return 0L; } - public void selectAreas(SelectAreasResponseCallback callback, @Nullable ArrayList newAreas) { + public void selectAreas(SelectAreasResponseCallback callback, ArrayList newAreas) { selectAreas(callback, newAreas, 0); } - public void selectAreas(SelectAreasResponseCallback callback, @Nullable ArrayList newAreas, int timedInvokeTimeoutMs) { + public void selectAreas(SelectAreasResponseCallback callback, ArrayList newAreas, int timedInvokeTimeoutMs) { final long commandId = 0L; ArrayList elements = new ArrayList<>(); final long newAreasFieldID = 0L; - BaseTLVType newAreastlvValue = newAreas != null ? ArrayType.generateArrayType(newAreas, (elementnewAreas) -> new UIntType(elementnewAreas)) : new NullType(); + BaseTLVType newAreastlvValue = ArrayType.generateArrayType(newAreas, (elementnewAreas) -> new UIntType(elementnewAreas)); elements.add(new StructElement(newAreasFieldID, newAreastlvValue)); StructType commandArgs = new StructType(elements); @@ -39156,11 +39156,11 @@ public interface SupportedAreasAttributeCallback extends BaseAttributeCallback { } public interface SupportedMapsAttributeCallback extends BaseAttributeCallback { - void onSuccess(@Nullable List value); + void onSuccess(List value); } public interface SelectedAreasAttributeCallback extends BaseAttributeCallback { - void onSuccess(@Nullable List value); + void onSuccess(List value); } public interface CurrentAreaAttributeCallback extends BaseAttributeCallback { @@ -39172,7 +39172,7 @@ public interface EstimatedEndTimeAttributeCallback extends BaseAttributeCallback } public interface ProgressAttributeCallback extends BaseAttributeCallback { - void onSuccess(@Nullable List value); + void onSuccess(List value); } public interface GeneratedCommandListAttributeCallback extends BaseAttributeCallback { @@ -39224,7 +39224,7 @@ public void readSupportedMapsAttribute( readAttribute(new ReportCallbackImpl(callback, path) { @Override public void onSuccess(byte[] tlv) { - @Nullable List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } }, SUPPORTED_MAPS_ATTRIBUTE_ID, true); @@ -39237,7 +39237,7 @@ public void subscribeSupportedMapsAttribute( subscribeAttribute(new ReportCallbackImpl(callback, path) { @Override public void onSuccess(byte[] tlv) { - @Nullable List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } }, SUPPORTED_MAPS_ATTRIBUTE_ID, minInterval, maxInterval); @@ -39250,7 +39250,7 @@ public void readSelectedAreasAttribute( readAttribute(new ReportCallbackImpl(callback, path) { @Override public void onSuccess(byte[] tlv) { - @Nullable List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } }, SELECTED_AREAS_ATTRIBUTE_ID, true); @@ -39263,7 +39263,7 @@ public void subscribeSelectedAreasAttribute( subscribeAttribute(new ReportCallbackImpl(callback, path) { @Override public void onSuccess(byte[] tlv) { - @Nullable List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } }, SELECTED_AREAS_ATTRIBUTE_ID, minInterval, maxInterval); @@ -39328,7 +39328,7 @@ public void readProgressAttribute( readAttribute(new ReportCallbackImpl(callback, path) { @Override public void onSuccess(byte[] tlv) { - @Nullable List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } }, PROGRESS_ATTRIBUTE_ID, true); @@ -39341,7 +39341,7 @@ public void subscribeProgressAttribute( subscribeAttribute(new ReportCallbackImpl(callback, path) { @Override public void onSuccess(byte[] tlv) { - @Nullable List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); + List value = ChipTLVValueDecoder.decodeAttributeValue(path, tlv); callback.onSuccess(value); } }, PROGRESS_ATTRIBUTE_ID, minInterval, maxInterval); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java index 7b3f36e2f0fb83..d2703a0146de5a 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java @@ -13193,7 +13193,7 @@ public void setCallbackDelegate(ClusterCommandCallback callback) { } @Override - public void onSuccess(@Nullable List valueList) { + public void onSuccess(List valueList) { Map responseValues = new LinkedHashMap<>(); CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); responseValues.put(commandResponseInfo, valueList); @@ -13214,7 +13214,7 @@ public void setCallbackDelegate(ClusterCommandCallback callback) { } @Override - public void onSuccess(@Nullable List valueList) { + public void onSuccess(List valueList) { Map responseValues = new LinkedHashMap<>(); CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); responseValues.put(commandResponseInfo, valueList); @@ -13277,7 +13277,7 @@ public void setCallbackDelegate(ClusterCommandCallback callback) { } @Override - public void onSuccess(@Nullable List valueList) { + public void onSuccess(List valueList) { Map responseValues = new LinkedHashMap<>(); CommandResponseInfo commandResponseInfo = new CommandResponseInfo("valueList", "List"); responseValues.put(commandResponseInfo, valueList); diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/ServiceAreaCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/ServiceAreaCluster.kt index 3f7aad29ed5a42..08376006435cf1 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/ServiceAreaCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/ServiceAreaCluster.kt @@ -55,10 +55,10 @@ class ServiceAreaCluster(private val controller: MatterController, private val e object SubscriptionEstablished : SupportedAreasAttributeSubscriptionState() } - class SupportedMapsAttribute(val value: List?) + class SupportedMapsAttribute(val value: List) sealed class SupportedMapsAttributeSubscriptionState { - data class Success(val value: List?) : + data class Success(val value: List) : SupportedMapsAttributeSubscriptionState() data class Error(val exception: Exception) : SupportedMapsAttributeSubscriptionState() @@ -66,10 +66,10 @@ class ServiceAreaCluster(private val controller: MatterController, private val e object SubscriptionEstablished : SupportedMapsAttributeSubscriptionState() } - class SelectedAreasAttribute(val value: List?) + class SelectedAreasAttribute(val value: List) sealed class SelectedAreasAttributeSubscriptionState { - data class Success(val value: List?) : SelectedAreasAttributeSubscriptionState() + data class Success(val value: List) : SelectedAreasAttributeSubscriptionState() data class Error(val exception: Exception) : SelectedAreasAttributeSubscriptionState() @@ -148,7 +148,7 @@ class ServiceAreaCluster(private val controller: MatterController, private val e } suspend fun selectAreas( - newAreas: List?, + newAreas: List, timedInvokeTimeout: Duration? = null, ): SelectAreasResponse { val commandId: UInt = 0u @@ -157,13 +157,11 @@ class ServiceAreaCluster(private val controller: MatterController, private val e tlvWriter.startStructure(AnonymousTag) val TAG_NEW_AREAS_REQ: Int = 0 - newAreas?.let { - tlvWriter.startArray(ContextSpecificTag(TAG_NEW_AREAS_REQ)) - for (item in newAreas.iterator()) { - tlvWriter.put(AnonymousTag, item) - } - tlvWriter.endArray() + tlvWriter.startArray(ContextSpecificTag(TAG_NEW_AREAS_REQ)) + for (item in newAreas.iterator()) { + tlvWriter.put(AnonymousTag, item) } + tlvWriter.endArray() tlvWriter.endStructure() val request: InvokeRequest = @@ -398,18 +396,13 @@ class ServiceAreaCluster(private val controller: MatterController, private val e // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) - val decodedValue: List? = - if (!tlvReader.isNull()) { - buildList { - tlvReader.enterArray(AnonymousTag) - while (!tlvReader.isEndOfContainer()) { - add(ServiceAreaClusterMapStruct.fromTlv(AnonymousTag, tlvReader)) - } - tlvReader.exitContainer() + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(ServiceAreaClusterMapStruct.fromTlv(AnonymousTag, tlvReader)) } - } else { - tlvReader.getNull(AnonymousTag) - null + tlvReader.exitContainer() } return SupportedMapsAttribute(decodedValue) @@ -454,21 +447,16 @@ class ServiceAreaCluster(private val controller: MatterController, private val e // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) - val decodedValue: List? = - if (!tlvReader.isNull()) { - buildList { - tlvReader.enterArray(AnonymousTag) - while (!tlvReader.isEndOfContainer()) { - add(ServiceAreaClusterMapStruct.fromTlv(AnonymousTag, tlvReader)) - } - tlvReader.exitContainer() + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(ServiceAreaClusterMapStruct.fromTlv(AnonymousTag, tlvReader)) } - } else { - tlvReader.getNull(AnonymousTag) - null + tlvReader.exitContainer() } - decodedValue?.let { emit(SupportedMapsAttributeSubscriptionState.Success(it)) } + emit(SupportedMapsAttributeSubscriptionState.Success(decodedValue)) } SubscriptionState.SubscriptionEstablished -> { emit(SupportedMapsAttributeSubscriptionState.SubscriptionEstablished) @@ -503,18 +491,13 @@ class ServiceAreaCluster(private val controller: MatterController, private val e // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) - val decodedValue: List? = - if (!tlvReader.isNull()) { - buildList { - tlvReader.enterArray(AnonymousTag) - while (!tlvReader.isEndOfContainer()) { - add(tlvReader.getUInt(AnonymousTag)) - } - tlvReader.exitContainer() + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) } - } else { - tlvReader.getNull(AnonymousTag) - null + tlvReader.exitContainer() } return SelectedAreasAttribute(decodedValue) @@ -559,21 +542,16 @@ class ServiceAreaCluster(private val controller: MatterController, private val e // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) - val decodedValue: List? = - if (!tlvReader.isNull()) { - buildList { - tlvReader.enterArray(AnonymousTag) - while (!tlvReader.isEndOfContainer()) { - add(tlvReader.getUInt(AnonymousTag)) - } - tlvReader.exitContainer() + val decodedValue: List = + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(tlvReader.getUInt(AnonymousTag)) } - } else { - tlvReader.getNull(AnonymousTag) - null + tlvReader.exitContainer() } - decodedValue?.let { emit(SelectedAreasAttributeSubscriptionState.Success(it)) } + emit(SelectedAreasAttributeSubscriptionState.Success(decodedValue)) } SubscriptionState.SubscriptionEstablished -> { emit(SelectedAreasAttributeSubscriptionState.SubscriptionEstablished) @@ -813,20 +791,15 @@ class ServiceAreaCluster(private val controller: MatterController, private val e // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) val decodedValue: List? = - if (!tlvReader.isNull()) { - if (tlvReader.isNextTag(AnonymousTag)) { - buildList { - tlvReader.enterArray(AnonymousTag) - while (!tlvReader.isEndOfContainer()) { - add(ServiceAreaClusterProgressStruct.fromTlv(AnonymousTag, tlvReader)) - } - tlvReader.exitContainer() + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(ServiceAreaClusterProgressStruct.fromTlv(AnonymousTag, tlvReader)) } - } else { - null + tlvReader.exitContainer() } } else { - tlvReader.getNull(AnonymousTag) null } @@ -873,20 +846,15 @@ class ServiceAreaCluster(private val controller: MatterController, private val e // Decode the TLV data into the appropriate type val tlvReader = TlvReader(attributeData.data) val decodedValue: List? = - if (!tlvReader.isNull()) { - if (tlvReader.isNextTag(AnonymousTag)) { - buildList { - tlvReader.enterArray(AnonymousTag) - while (!tlvReader.isEndOfContainer()) { - add(ServiceAreaClusterProgressStruct.fromTlv(AnonymousTag, tlvReader)) - } - tlvReader.exitContainer() + if (tlvReader.isNextTag(AnonymousTag)) { + buildList { + tlvReader.enterArray(AnonymousTag) + while (!tlvReader.isEndOfContainer()) { + add(ServiceAreaClusterProgressStruct.fromTlv(AnonymousTag, tlvReader)) } - } else { - null + tlvReader.exitContainer() } } else { - tlvReader.getNull(AnonymousTag) null } diff --git a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp index 81cd1313270c54..ebcec56cd2b41a 100644 --- a/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp +++ b/src/controller/java/zap-generated/CHIPAttributeTLVValueDecoder.cpp @@ -28819,51 +28819,43 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR return nullptr; } jobject value; - if (cppValue.IsNull()) - { - value = nullptr; - } - else + chip::JniReferences::GetInstance().CreateArrayList(value); + + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) { - chip::JniReferences::GetInstance().CreateArrayList(value); + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + jobject newElement_0_mapID; + std::string newElement_0_mapIDClassName = "java/lang/Integer"; + std::string newElement_0_mapIDCtorSignature = "(I)V"; + jint jninewElement_0_mapID = static_cast(entry_0.mapID); + chip::JniReferences::GetInstance().CreateBoxedObject(newElement_0_mapIDClassName.c_str(), + newElement_0_mapIDCtorSignature.c_str(), + jninewElement_0_mapID, newElement_0_mapID); + jobject newElement_0_name; + LogErrorOnFailure(chip::JniReferences::GetInstance().CharToStringUTF(entry_0.name, newElement_0_name)); - auto iter_value_1 = cppValue.Value().begin(); - while (iter_value_1.Next()) + jclass mapStructStructClass_1; + err = chip::JniReferences::GetInstance().GetLocalClassRef( + env, "chip/devicecontroller/ChipStructs$ServiceAreaClusterMapStruct", mapStructStructClass_1); + if (err != CHIP_NO_ERROR) { - auto & entry_1 = iter_value_1.GetValue(); - jobject newElement_1; - jobject newElement_1_mapID; - std::string newElement_1_mapIDClassName = "java/lang/Integer"; - std::string newElement_1_mapIDCtorSignature = "(I)V"; - jint jninewElement_1_mapID = static_cast(entry_1.mapID); - chip::JniReferences::GetInstance().CreateBoxedObject(newElement_1_mapIDClassName.c_str(), - newElement_1_mapIDCtorSignature.c_str(), - jninewElement_1_mapID, newElement_1_mapID); - jobject newElement_1_name; - LogErrorOnFailure(chip::JniReferences::GetInstance().CharToStringUTF(entry_1.name, newElement_1_name)); - - jclass mapStructStructClass_2; - err = chip::JniReferences::GetInstance().GetLocalClassRef( - env, "chip/devicecontroller/ChipStructs$ServiceAreaClusterMapStruct", mapStructStructClass_2); - if (err != CHIP_NO_ERROR) - { - ChipLogError(Zcl, "Could not find class ChipStructs$ServiceAreaClusterMapStruct"); - return nullptr; - } - - jmethodID mapStructStructCtor_2; - err = chip::JniReferences::GetInstance().FindMethod( - env, mapStructStructClass_2, "", "(Ljava/lang/Integer;Ljava/lang/String;)V", &mapStructStructCtor_2); - if (err != CHIP_NO_ERROR || mapStructStructCtor_2 == nullptr) - { - ChipLogError(Zcl, "Could not find ChipStructs$ServiceAreaClusterMapStruct constructor"); - return nullptr; - } + ChipLogError(Zcl, "Could not find class ChipStructs$ServiceAreaClusterMapStruct"); + return nullptr; + } - newElement_1 = - env->NewObject(mapStructStructClass_2, mapStructStructCtor_2, newElement_1_mapID, newElement_1_name); - chip::JniReferences::GetInstance().AddToList(value, newElement_1); + jmethodID mapStructStructCtor_1; + err = chip::JniReferences::GetInstance().FindMethod( + env, mapStructStructClass_1, "", "(Ljava/lang/Integer;Ljava/lang/String;)V", &mapStructStructCtor_1); + if (err != CHIP_NO_ERROR || mapStructStructCtor_1 == nullptr) + { + ChipLogError(Zcl, "Could not find ChipStructs$ServiceAreaClusterMapStruct constructor"); + return nullptr; } + + newElement_0 = env->NewObject(mapStructStructClass_1, mapStructStructCtor_1, newElement_0_mapID, newElement_0_name); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); } return value; } @@ -28876,26 +28868,19 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR return nullptr; } jobject value; - if (cppValue.IsNull()) - { - value = nullptr; - } - else - { - chip::JniReferences::GetInstance().CreateArrayList(value); + chip::JniReferences::GetInstance().CreateArrayList(value); - auto iter_value_1 = cppValue.Value().begin(); - while (iter_value_1.Next()) - { - auto & entry_1 = iter_value_1.GetValue(); - jobject newElement_1; - std::string newElement_1ClassName = "java/lang/Long"; - std::string newElement_1CtorSignature = "(J)V"; - jlong jninewElement_1 = static_cast(entry_1); - chip::JniReferences::GetInstance().CreateBoxedObject( - newElement_1ClassName.c_str(), newElement_1CtorSignature.c_str(), jninewElement_1, newElement_1); - chip::JniReferences::GetInstance().AddToList(value, newElement_1); - } + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + std::string newElement_0ClassName = "java/lang/Long"; + std::string newElement_0CtorSignature = "(J)V"; + jlong jninewElement_0 = static_cast(entry_0); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0ClassName.c_str(), newElement_0CtorSignature.c_str(), jninewElement_0, newElement_0); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); } return value; } @@ -28954,112 +28939,102 @@ jobject DecodeAttributeValue(const app::ConcreteAttributePath & aPath, TLV::TLVR return nullptr; } jobject value; - if (cppValue.IsNull()) - { - value = nullptr; - } - else - { - chip::JniReferences::GetInstance().CreateArrayList(value); + chip::JniReferences::GetInstance().CreateArrayList(value); - auto iter_value_1 = cppValue.Value().begin(); - while (iter_value_1.Next()) + auto iter_value_0 = cppValue.begin(); + while (iter_value_0.Next()) + { + auto & entry_0 = iter_value_0.GetValue(); + jobject newElement_0; + jobject newElement_0_areaID; + std::string newElement_0_areaIDClassName = "java/lang/Long"; + std::string newElement_0_areaIDCtorSignature = "(J)V"; + jlong jninewElement_0_areaID = static_cast(entry_0.areaID); + chip::JniReferences::GetInstance().CreateBoxedObject(newElement_0_areaIDClassName.c_str(), + newElement_0_areaIDCtorSignature.c_str(), + jninewElement_0_areaID, newElement_0_areaID); + jobject newElement_0_status; + std::string newElement_0_statusClassName = "java/lang/Integer"; + std::string newElement_0_statusCtorSignature = "(I)V"; + jint jninewElement_0_status = static_cast(entry_0.status); + chip::JniReferences::GetInstance().CreateBoxedObject(newElement_0_statusClassName.c_str(), + newElement_0_statusCtorSignature.c_str(), + jninewElement_0_status, newElement_0_status); + jobject newElement_0_totalOperationalTime; + if (!entry_0.totalOperationalTime.HasValue()) + { + chip::JniReferences::GetInstance().CreateOptional(nullptr, newElement_0_totalOperationalTime); + } + else { - auto & entry_1 = iter_value_1.GetValue(); - jobject newElement_1; - jobject newElement_1_areaID; - std::string newElement_1_areaIDClassName = "java/lang/Long"; - std::string newElement_1_areaIDCtorSignature = "(J)V"; - jlong jninewElement_1_areaID = static_cast(entry_1.areaID); - chip::JniReferences::GetInstance().CreateBoxedObject(newElement_1_areaIDClassName.c_str(), - newElement_1_areaIDCtorSignature.c_str(), - jninewElement_1_areaID, newElement_1_areaID); - jobject newElement_1_status; - std::string newElement_1_statusClassName = "java/lang/Integer"; - std::string newElement_1_statusCtorSignature = "(I)V"; - jint jninewElement_1_status = static_cast(entry_1.status); - chip::JniReferences::GetInstance().CreateBoxedObject(newElement_1_statusClassName.c_str(), - newElement_1_statusCtorSignature.c_str(), - jninewElement_1_status, newElement_1_status); - jobject newElement_1_totalOperationalTime; - if (!entry_1.totalOperationalTime.HasValue()) + jobject newElement_0_totalOperationalTimeInsideOptional; + if (entry_0.totalOperationalTime.Value().IsNull()) { - chip::JniReferences::GetInstance().CreateOptional(nullptr, newElement_1_totalOperationalTime); + newElement_0_totalOperationalTimeInsideOptional = nullptr; } else { - jobject newElement_1_totalOperationalTimeInsideOptional; - if (entry_1.totalOperationalTime.Value().IsNull()) - { - newElement_1_totalOperationalTimeInsideOptional = nullptr; - } - else - { - std::string newElement_1_totalOperationalTimeInsideOptionalClassName = "java/lang/Long"; - std::string newElement_1_totalOperationalTimeInsideOptionalCtorSignature = "(J)V"; - jlong jninewElement_1_totalOperationalTimeInsideOptional = - static_cast(entry_1.totalOperationalTime.Value().Value()); - chip::JniReferences::GetInstance().CreateBoxedObject( - newElement_1_totalOperationalTimeInsideOptionalClassName.c_str(), - newElement_1_totalOperationalTimeInsideOptionalCtorSignature.c_str(), - jninewElement_1_totalOperationalTimeInsideOptional, - newElement_1_totalOperationalTimeInsideOptional); - } - chip::JniReferences::GetInstance().CreateOptional(newElement_1_totalOperationalTimeInsideOptional, - newElement_1_totalOperationalTime); + std::string newElement_0_totalOperationalTimeInsideOptionalClassName = "java/lang/Long"; + std::string newElement_0_totalOperationalTimeInsideOptionalCtorSignature = "(J)V"; + jlong jninewElement_0_totalOperationalTimeInsideOptional = + static_cast(entry_0.totalOperationalTime.Value().Value()); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0_totalOperationalTimeInsideOptionalClassName.c_str(), + newElement_0_totalOperationalTimeInsideOptionalCtorSignature.c_str(), + jninewElement_0_totalOperationalTimeInsideOptional, newElement_0_totalOperationalTimeInsideOptional); } - jobject newElement_1_estimatedTime; - if (!entry_1.estimatedTime.HasValue()) + chip::JniReferences::GetInstance().CreateOptional(newElement_0_totalOperationalTimeInsideOptional, + newElement_0_totalOperationalTime); + } + jobject newElement_0_estimatedTime; + if (!entry_0.estimatedTime.HasValue()) + { + chip::JniReferences::GetInstance().CreateOptional(nullptr, newElement_0_estimatedTime); + } + else + { + jobject newElement_0_estimatedTimeInsideOptional; + if (entry_0.estimatedTime.Value().IsNull()) { - chip::JniReferences::GetInstance().CreateOptional(nullptr, newElement_1_estimatedTime); + newElement_0_estimatedTimeInsideOptional = nullptr; } else { - jobject newElement_1_estimatedTimeInsideOptional; - if (entry_1.estimatedTime.Value().IsNull()) - { - newElement_1_estimatedTimeInsideOptional = nullptr; - } - else - { - std::string newElement_1_estimatedTimeInsideOptionalClassName = "java/lang/Long"; - std::string newElement_1_estimatedTimeInsideOptionalCtorSignature = "(J)V"; - jlong jninewElement_1_estimatedTimeInsideOptional = - static_cast(entry_1.estimatedTime.Value().Value()); - chip::JniReferences::GetInstance().CreateBoxedObject( - newElement_1_estimatedTimeInsideOptionalClassName.c_str(), - newElement_1_estimatedTimeInsideOptionalCtorSignature.c_str(), - jninewElement_1_estimatedTimeInsideOptional, newElement_1_estimatedTimeInsideOptional); - } - chip::JniReferences::GetInstance().CreateOptional(newElement_1_estimatedTimeInsideOptional, - newElement_1_estimatedTime); - } - - jclass progressStructStructClass_2; - err = chip::JniReferences::GetInstance().GetLocalClassRef( - env, "chip/devicecontroller/ChipStructs$ServiceAreaClusterProgressStruct", progressStructStructClass_2); - if (err != CHIP_NO_ERROR) - { - ChipLogError(Zcl, "Could not find class ChipStructs$ServiceAreaClusterProgressStruct"); - return nullptr; + std::string newElement_0_estimatedTimeInsideOptionalClassName = "java/lang/Long"; + std::string newElement_0_estimatedTimeInsideOptionalCtorSignature = "(J)V"; + jlong jninewElement_0_estimatedTimeInsideOptional = + static_cast(entry_0.estimatedTime.Value().Value()); + chip::JniReferences::GetInstance().CreateBoxedObject( + newElement_0_estimatedTimeInsideOptionalClassName.c_str(), + newElement_0_estimatedTimeInsideOptionalCtorSignature.c_str(), + jninewElement_0_estimatedTimeInsideOptional, newElement_0_estimatedTimeInsideOptional); } + chip::JniReferences::GetInstance().CreateOptional(newElement_0_estimatedTimeInsideOptional, + newElement_0_estimatedTime); + } - jmethodID progressStructStructCtor_2; - err = chip::JniReferences::GetInstance().FindMethod( - env, progressStructStructClass_2, "", - "(Ljava/lang/Long;Ljava/lang/Integer;Ljava/util/Optional;Ljava/util/Optional;)V", - &progressStructStructCtor_2); - if (err != CHIP_NO_ERROR || progressStructStructCtor_2 == nullptr) - { - ChipLogError(Zcl, "Could not find ChipStructs$ServiceAreaClusterProgressStruct constructor"); - return nullptr; - } + jclass progressStructStructClass_1; + err = chip::JniReferences::GetInstance().GetLocalClassRef( + env, "chip/devicecontroller/ChipStructs$ServiceAreaClusterProgressStruct", progressStructStructClass_1); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Zcl, "Could not find class ChipStructs$ServiceAreaClusterProgressStruct"); + return nullptr; + } - newElement_1 = - env->NewObject(progressStructStructClass_2, progressStructStructCtor_2, newElement_1_areaID, - newElement_1_status, newElement_1_totalOperationalTime, newElement_1_estimatedTime); - chip::JniReferences::GetInstance().AddToList(value, newElement_1); + jmethodID progressStructStructCtor_1; + err = chip::JniReferences::GetInstance().FindMethod( + env, progressStructStructClass_1, "", + "(Ljava/lang/Long;Ljava/lang/Integer;Ljava/util/Optional;Ljava/util/Optional;)V", &progressStructStructCtor_1); + if (err != CHIP_NO_ERROR || progressStructStructCtor_1 == nullptr) + { + ChipLogError(Zcl, "Could not find ChipStructs$ServiceAreaClusterProgressStruct constructor"); + return nullptr; } + + newElement_0 = env->NewObject(progressStructStructClass_1, progressStructStructCtor_1, newElement_0_areaID, + newElement_0_status, newElement_0_totalOperationalTime, newElement_0_estimatedTime); + chip::JniReferences::GetInstance().AddToList(value, newElement_0); } return value; } diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index 5f1ca74314b3a3..670c7109a5ccb8 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -31144,11 +31144,11 @@ def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ ClusterObjectFieldDescriptor(Label="supportedAreas", Tag=0x00000000, Type=typing.List[ServiceArea.Structs.AreaStruct]), - ClusterObjectFieldDescriptor(Label="supportedMaps", Tag=0x00000001, Type=typing.Union[Nullable, typing.List[ServiceArea.Structs.MapStruct]]), - ClusterObjectFieldDescriptor(Label="selectedAreas", Tag=0x00000002, Type=typing.Union[Nullable, typing.List[uint]]), + ClusterObjectFieldDescriptor(Label="supportedMaps", Tag=0x00000001, Type=typing.List[ServiceArea.Structs.MapStruct]), + ClusterObjectFieldDescriptor(Label="selectedAreas", Tag=0x00000002, Type=typing.List[uint]), ClusterObjectFieldDescriptor(Label="currentArea", Tag=0x00000003, Type=typing.Union[None, Nullable, uint]), ClusterObjectFieldDescriptor(Label="estimatedEndTime", Tag=0x00000004, Type=typing.Union[None, Nullable, uint]), - ClusterObjectFieldDescriptor(Label="progress", Tag=0x00000005, Type=typing.Union[None, Nullable, typing.List[ServiceArea.Structs.ProgressStruct]]), + ClusterObjectFieldDescriptor(Label="progress", Tag=0x00000005, Type=typing.Optional[typing.List[ServiceArea.Structs.ProgressStruct]]), ClusterObjectFieldDescriptor(Label="generatedCommandList", Tag=0x0000FFF8, Type=typing.List[uint]), ClusterObjectFieldDescriptor(Label="acceptedCommandList", Tag=0x0000FFF9, Type=typing.List[uint]), ClusterObjectFieldDescriptor(Label="eventList", Tag=0x0000FFFA, Type=typing.List[uint]), @@ -31158,11 +31158,11 @@ def descriptor(cls) -> ClusterObjectDescriptor: ]) supportedAreas: 'typing.List[ServiceArea.Structs.AreaStruct]' = None - supportedMaps: 'typing.Union[Nullable, typing.List[ServiceArea.Structs.MapStruct]]' = None - selectedAreas: 'typing.Union[Nullable, typing.List[uint]]' = None + supportedMaps: 'typing.List[ServiceArea.Structs.MapStruct]' = None + selectedAreas: 'typing.List[uint]' = None currentArea: 'typing.Union[None, Nullable, uint]' = None estimatedEndTime: 'typing.Union[None, Nullable, uint]' = None - progress: 'typing.Union[None, Nullable, typing.List[ServiceArea.Structs.ProgressStruct]]' = None + progress: 'typing.Optional[typing.List[ServiceArea.Structs.ProgressStruct]]' = None generatedCommandList: 'typing.List[uint]' = None acceptedCommandList: 'typing.List[uint]' = None eventList: 'typing.List[uint]' = None @@ -31284,10 +31284,10 @@ class SelectAreas(ClusterCommand): def descriptor(cls) -> ClusterObjectDescriptor: return ClusterObjectDescriptor( Fields=[ - ClusterObjectFieldDescriptor(Label="newAreas", Tag=0, Type=typing.Union[Nullable, typing.List[uint]]), + ClusterObjectFieldDescriptor(Label="newAreas", Tag=0, Type=typing.List[uint]), ]) - newAreas: 'typing.Union[Nullable, typing.List[uint]]' = NullValue + newAreas: 'typing.List[uint]' = field(default_factory=lambda: []) @dataclass class SelectAreasResponse(ClusterCommand): @@ -31367,9 +31367,9 @@ def attribute_id(cls) -> int: @ChipUtility.classproperty def attribute_type(cls) -> ClusterObjectFieldDescriptor: - return ClusterObjectFieldDescriptor(Type=typing.Union[Nullable, typing.List[ServiceArea.Structs.MapStruct]]) + return ClusterObjectFieldDescriptor(Type=typing.List[ServiceArea.Structs.MapStruct]) - value: 'typing.Union[Nullable, typing.List[ServiceArea.Structs.MapStruct]]' = NullValue + value: 'typing.List[ServiceArea.Structs.MapStruct]' = field(default_factory=lambda: []) @dataclass class SelectedAreas(ClusterAttributeDescriptor): @@ -31383,9 +31383,9 @@ def attribute_id(cls) -> int: @ChipUtility.classproperty def attribute_type(cls) -> ClusterObjectFieldDescriptor: - return ClusterObjectFieldDescriptor(Type=typing.Union[Nullable, typing.List[uint]]) + return ClusterObjectFieldDescriptor(Type=typing.List[uint]) - value: 'typing.Union[Nullable, typing.List[uint]]' = NullValue + value: 'typing.List[uint]' = field(default_factory=lambda: []) @dataclass class CurrentArea(ClusterAttributeDescriptor): @@ -31431,9 +31431,9 @@ def attribute_id(cls) -> int: @ChipUtility.classproperty def attribute_type(cls) -> ClusterObjectFieldDescriptor: - return ClusterObjectFieldDescriptor(Type=typing.Union[None, Nullable, typing.List[ServiceArea.Structs.ProgressStruct]]) + return ClusterObjectFieldDescriptor(Type=typing.Optional[typing.List[ServiceArea.Structs.ProgressStruct]]) - value: 'typing.Union[None, Nullable, typing.List[ServiceArea.Structs.ProgressStruct]]' = None + value: 'typing.Optional[typing.List[ServiceArea.Structs.ProgressStruct]]' = None @dataclass class GeneratedCommandList(ClusterAttributeDescriptor): diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm index b1c3fb9d486ca5..95001d3ca68720 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRAttributeTLVValueDecoder.mm @@ -11252,33 +11252,29 @@ static id _Nullable DecodeAttributeValueForServiceAreaCluster(AttributeId aAttri if (*aError != CHIP_NO_ERROR) { return nil; } - NSArray * _Nullable value; - if (cppValue.IsNull()) { - value = nil; - } else { - { // Scope for our temporary variables - auto * array_1 = [NSMutableArray new]; - auto iter_1 = cppValue.Value().begin(); - while (iter_1.Next()) { - auto & entry_1 = iter_1.GetValue(); - MTRServiceAreaClusterMapStruct * newElement_1; - newElement_1 = [MTRServiceAreaClusterMapStruct new]; - newElement_1.mapID = [NSNumber numberWithUnsignedChar:entry_1.mapID]; - newElement_1.name = AsString(entry_1.name); - if (newElement_1.name == nil) { - CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; - *aError = err; - return nil; - } - [array_1 addObject:newElement_1]; - } - CHIP_ERROR err = iter_1.GetStatus(); - if (err != CHIP_NO_ERROR) { + NSArray * _Nonnull value; + { // Scope for our temporary variables + auto * array_0 = [NSMutableArray new]; + auto iter_0 = cppValue.begin(); + while (iter_0.Next()) { + auto & entry_0 = iter_0.GetValue(); + MTRServiceAreaClusterMapStruct * newElement_0; + newElement_0 = [MTRServiceAreaClusterMapStruct new]; + newElement_0.mapID = [NSNumber numberWithUnsignedChar:entry_0.mapID]; + newElement_0.name = AsString(entry_0.name); + if (newElement_0.name == nil) { + CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; *aError = err; return nil; } - value = array_1; + [array_0 addObject:newElement_0]; + } + CHIP_ERROR err = iter_0.GetStatus(); + if (err != CHIP_NO_ERROR) { + *aError = err; + return nil; } + value = array_0; } return value; } @@ -11289,26 +11285,22 @@ static id _Nullable DecodeAttributeValueForServiceAreaCluster(AttributeId aAttri if (*aError != CHIP_NO_ERROR) { return nil; } - NSArray * _Nullable value; - if (cppValue.IsNull()) { - value = nil; - } else { - { // Scope for our temporary variables - auto * array_1 = [NSMutableArray new]; - auto iter_1 = cppValue.Value().begin(); - while (iter_1.Next()) { - auto & entry_1 = iter_1.GetValue(); - NSNumber * newElement_1; - newElement_1 = [NSNumber numberWithUnsignedInt:entry_1]; - [array_1 addObject:newElement_1]; - } - CHIP_ERROR err = iter_1.GetStatus(); - if (err != CHIP_NO_ERROR) { - *aError = err; - return nil; - } - value = array_1; + NSArray * _Nonnull value; + { // Scope for our temporary variables + auto * array_0 = [NSMutableArray new]; + auto iter_0 = cppValue.begin(); + while (iter_0.Next()) { + auto & entry_0 = iter_0.GetValue(); + NSNumber * newElement_0; + newElement_0 = [NSNumber numberWithUnsignedInt:entry_0]; + [array_0 addObject:newElement_0]; + } + CHIP_ERROR err = iter_0.GetStatus(); + if (err != CHIP_NO_ERROR) { + *aError = err; + return nil; } + value = array_0; } return value; } @@ -11349,46 +11341,42 @@ static id _Nullable DecodeAttributeValueForServiceAreaCluster(AttributeId aAttri if (*aError != CHIP_NO_ERROR) { return nil; } - NSArray * _Nullable value; - if (cppValue.IsNull()) { - value = nil; - } else { - { // Scope for our temporary variables - auto * array_1 = [NSMutableArray new]; - auto iter_1 = cppValue.Value().begin(); - while (iter_1.Next()) { - auto & entry_1 = iter_1.GetValue(); - MTRServiceAreaClusterProgressStruct * newElement_1; - newElement_1 = [MTRServiceAreaClusterProgressStruct new]; - newElement_1.areaID = [NSNumber numberWithUnsignedInt:entry_1.areaID]; - newElement_1.status = [NSNumber numberWithUnsignedChar:chip::to_underlying(entry_1.status)]; - if (entry_1.totalOperationalTime.HasValue()) { - if (entry_1.totalOperationalTime.Value().IsNull()) { - newElement_1.totalOperationalTime = nil; - } else { - newElement_1.totalOperationalTime = [NSNumber numberWithUnsignedInt:entry_1.totalOperationalTime.Value().Value()]; - } + NSArray * _Nonnull value; + { // Scope for our temporary variables + auto * array_0 = [NSMutableArray new]; + auto iter_0 = cppValue.begin(); + while (iter_0.Next()) { + auto & entry_0 = iter_0.GetValue(); + MTRServiceAreaClusterProgressStruct * newElement_0; + newElement_0 = [MTRServiceAreaClusterProgressStruct new]; + newElement_0.areaID = [NSNumber numberWithUnsignedInt:entry_0.areaID]; + newElement_0.status = [NSNumber numberWithUnsignedChar:chip::to_underlying(entry_0.status)]; + if (entry_0.totalOperationalTime.HasValue()) { + if (entry_0.totalOperationalTime.Value().IsNull()) { + newElement_0.totalOperationalTime = nil; } else { - newElement_1.totalOperationalTime = nil; + newElement_0.totalOperationalTime = [NSNumber numberWithUnsignedInt:entry_0.totalOperationalTime.Value().Value()]; } - if (entry_1.estimatedTime.HasValue()) { - if (entry_1.estimatedTime.Value().IsNull()) { - newElement_1.estimatedTime = nil; - } else { - newElement_1.estimatedTime = [NSNumber numberWithUnsignedInt:entry_1.estimatedTime.Value().Value()]; - } + } else { + newElement_0.totalOperationalTime = nil; + } + if (entry_0.estimatedTime.HasValue()) { + if (entry_0.estimatedTime.Value().IsNull()) { + newElement_0.estimatedTime = nil; } else { - newElement_1.estimatedTime = nil; + newElement_0.estimatedTime = [NSNumber numberWithUnsignedInt:entry_0.estimatedTime.Value().Value()]; } - [array_1 addObject:newElement_1]; - } - CHIP_ERROR err = iter_1.GetStatus(); - if (err != CHIP_NO_ERROR) { - *aError = err; - return nil; + } else { + newElement_0.estimatedTime = nil; } - value = array_1; + [array_0 addObject:newElement_0]; } + CHIP_ERROR err = iter_0.GetStatus(); + if (err != CHIP_NO_ERROR) { + *aError = err; + return nil; + } + value = array_0; } return value; } diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index 88ef499858e1a7..79cc7d4011add6 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -7639,7 +7639,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) MTR_PROVISIONALLY_AVAILABLE @interface MTRServiceAreaClusterSelectAreasParams : NSObject -@property (nonatomic, copy, getter=getNewAreas) NSArray * _Nullable newAreas MTR_PROVISIONALLY_AVAILABLE; +@property (nonatomic, copy, getter=getNewAreas) NSArray * _Nonnull newAreas MTR_PROVISIONALLY_AVAILABLE; /** * Controls whether the command is a timed command (using Timed Invoke). * diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index 70f3cad514818b..eeb671df165fec 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -21789,7 +21789,7 @@ - (instancetype)init { if (self = [super init]) { - _newAreas = nil; + _newAreas = [NSArray array]; _timedInvokeTimeoutMs = nil; _serverSideProcessingTimeout = nil; } @@ -21822,31 +21822,26 @@ - (CHIP_ERROR)_encodeToTLVReader:(chip::System::PacketBufferTLVReader &)reader chip::app::Clusters::ServiceArea::Commands::SelectAreas::Type encodableStruct; ListFreer listFreer; { - if (self.newAreas == nil) { - encodableStruct.newAreas.SetNull(); - } else { - auto & nonNullValue_0 = encodableStruct.newAreas.SetNonNull(); - { - using ListType_1 = std::remove_reference_t; - using ListMemberType_1 = ListMemberTypeGetter::Type; - if (self.newAreas.count != 0) { - auto * listHolder_1 = new ListHolder(self.newAreas.count); - if (listHolder_1 == nullptr || listHolder_1->mList == nullptr) { + { + using ListType_0 = std::remove_reference_t; + using ListMemberType_0 = ListMemberTypeGetter::Type; + if (self.newAreas.count != 0) { + auto * listHolder_0 = new ListHolder(self.newAreas.count); + if (listHolder_0 == nullptr || listHolder_0->mList == nullptr) { + return CHIP_ERROR_INVALID_ARGUMENT; + } + listFreer.add(listHolder_0); + for (size_t i_0 = 0; i_0 < self.newAreas.count; ++i_0) { + if (![self.newAreas[i_0] isKindOfClass:[NSNumber class]]) { + // Wrong kind of value. return CHIP_ERROR_INVALID_ARGUMENT; } - listFreer.add(listHolder_1); - for (size_t i_1 = 0; i_1 < self.newAreas.count; ++i_1) { - if (![self.newAreas[i_1] isKindOfClass:[NSNumber class]]) { - // Wrong kind of value. - return CHIP_ERROR_INVALID_ARGUMENT; - } - auto element_1 = (NSNumber *) self.newAreas[i_1]; - listHolder_1->mList[i_1] = element_1.unsignedIntValue; - } - nonNullValue_0 = ListType_1(listHolder_1->mList, self.newAreas.count); - } else { - nonNullValue_0 = ListType_1(); + auto element_0 = (NSNumber *) self.newAreas[i_0]; + listHolder_0->mList[i_0] = element_0.unsignedIntValue; } + encodableStruct.newAreas = ListType_0(listHolder_0->mList, self.newAreas.count); + } else { + encodableStruct.newAreas = ListType_0(); } } } diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index f280ba39f8577c..07107feb2df637 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -28487,7 +28487,7 @@ struct Type static constexpr CommandId GetCommandId() { return Commands::SelectAreas::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } - DataModel::Nullable> newAreas; + DataModel::List newAreas; CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; @@ -28502,7 +28502,7 @@ struct DecodableType static constexpr CommandId GetCommandId() { return Commands::SelectAreas::Id; } static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } - DataModel::Nullable> newAreas; + DataModel::DecodableList newAreas; CHIP_ERROR Decode(TLV::TLVReader & reader); }; }; // namespace SelectAreas @@ -28624,12 +28624,10 @@ struct TypeInfo namespace SupportedMaps { struct TypeInfo { - using Type = chip::app::DataModel::Nullable< - chip::app::DataModel::List>; - using DecodableType = chip::app::DataModel::Nullable< - chip::app::DataModel::DecodableList>; - using DecodableArgType = const chip::app::DataModel::Nullable< - chip::app::DataModel::DecodableList> &; + using Type = chip::app::DataModel::List; + using DecodableType = chip::app::DataModel::DecodableList; + using DecodableArgType = + const chip::app::DataModel::DecodableList &; static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::SupportedMaps::Id; } @@ -28639,9 +28637,9 @@ struct TypeInfo namespace SelectedAreas { struct TypeInfo { - using Type = chip::app::DataModel::Nullable>; - using DecodableType = chip::app::DataModel::Nullable>; - using DecodableArgType = const chip::app::DataModel::Nullable> &; + using Type = chip::app::DataModel::List; + using DecodableType = chip::app::DataModel::DecodableList; + using DecodableArgType = const chip::app::DataModel::DecodableList &; static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::SelectedAreas::Id; } @@ -28675,12 +28673,11 @@ struct TypeInfo namespace Progress { struct TypeInfo { - using Type = chip::app::DataModel::Nullable< - chip::app::DataModel::List>; - using DecodableType = chip::app::DataModel::Nullable< - chip::app::DataModel::DecodableList>; - using DecodableArgType = const chip::app::DataModel::Nullable< - chip::app::DataModel::DecodableList> &; + using Type = chip::app::DataModel::List; + using DecodableType = + chip::app::DataModel::DecodableList; + using DecodableArgType = + const chip::app::DataModel::DecodableList &; static constexpr ClusterId GetClusterId() { return Clusters::ServiceArea::Id; } static constexpr AttributeId GetAttributeId() { return Attributes::Progress::Id; } diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index dd6fcb262adee4..98d6d9caee0e97 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -9418,7 +9418,7 @@ class ServiceAreaSelectAreas : public ClusterCommand private: chip::app::Clusters::ServiceArea::Commands::SelectAreas::Type mRequest; - TypedComplexArgument>> mComplex_NewAreas; + TypedComplexArgument> mComplex_NewAreas; }; /* @@ -22794,18 +22794,18 @@ void registerClusterServiceArea(Commands & commands, CredentialIssuerCommands * make_unique< WriteAttributeAsComplex>>( Id, "supported-areas", Attributes::SupportedAreas::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>>>( + make_unique< + WriteAttributeAsComplex>>( Id, "supported-maps", Attributes::SupportedMaps::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>>>( + make_unique>>( Id, "selected-areas", Attributes::SelectedAreas::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>>( Id, "current-area", 0, UINT32_MAX, Attributes::CurrentArea::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>>(Id, "estimated-end-time", 0, UINT32_MAX, Attributes::EstimatedEndTime::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // - make_unique>>>( + make_unique>>( Id, "progress", Attributes::Progress::Id, WriteCommandType::kForceWrite, credsIssuerConfig), // make_unique>>( Id, "generated-command-list", Attributes::GeneratedCommandList::Id, WriteCommandType::kForceWrite, diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp index 2e3b5bc55ddd6f..afebe69c9407ed 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp @@ -14739,14 +14739,12 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP return DataModelLogger::LogValue("SupportedAreas", 1, value); } case ServiceArea::Attributes::SupportedMaps::Id: { - chip::app::DataModel::Nullable< - chip::app::DataModel::DecodableList> - value; + chip::app::DataModel::DecodableList value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("SupportedMaps", 1, value); } case ServiceArea::Attributes::SelectedAreas::Id: { - chip::app::DataModel::Nullable> value; + chip::app::DataModel::DecodableList value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("SelectedAreas", 1, value); } @@ -14761,9 +14759,7 @@ CHIP_ERROR DataModelLogger::LogAttribute(const chip::app::ConcreteDataAttributeP return DataModelLogger::LogValue("EstimatedEndTime", 1, value); } case ServiceArea::Attributes::Progress::Id: { - chip::app::DataModel::Nullable< - chip::app::DataModel::DecodableList> - value; + chip::app::DataModel::DecodableList value; ReturnErrorOnFailure(chip::app::DataModel::Decode(*data, value)); return DataModelLogger::LogValue("Progress", 1, value); } diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index 195bf8b2a5a5b8..8e18e60aaa7e63 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -103900,18 +103900,14 @@ class ServiceAreaSelectAreas : public ClusterCommand { __auto_type * params = [[MTRServiceAreaClusterSelectAreasParams alloc] init]; params.timedInvokeTimeoutMs = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; #if MTR_ENABLE_PROVISIONAL - if (mRequest.newAreas.IsNull()) { - params.newAreas = nil; - } else { - { // Scope for our temporary variables - auto * array_1 = [NSMutableArray new]; - for (auto & entry_1 : mRequest.newAreas.Value()) { - NSNumber * newElement_1; - newElement_1 = [NSNumber numberWithUnsignedInt:entry_1]; - [array_1 addObject:newElement_1]; - } - params.newAreas = array_1; + { // Scope for our temporary variables + auto * array_0 = [NSMutableArray new]; + for (auto & entry_0 : mRequest.newAreas) { + NSNumber * newElement_0; + newElement_0 = [NSNumber numberWithUnsignedInt:entry_0]; + [array_0 addObject:newElement_0]; } + params.newAreas = array_0; } #endif // MTR_ENABLE_PROVISIONAL uint16_t repeatCount = mRepeatCount.ValueOr(1); @@ -103941,7 +103937,7 @@ class ServiceAreaSelectAreas : public ClusterCommand { private: chip::app::Clusters::ServiceArea::Commands::SelectAreas::Type mRequest; - TypedComplexArgument>> mComplex_NewAreas; + TypedComplexArgument> mComplex_NewAreas; }; #endif // MTR_ENABLE_PROVISIONAL From 83dc1c8c844c1db181a0c63ba29951e6ac19bcc9 Mon Sep 17 00:00:00 2001 From: Marius Tache <102153746+marius-alex-tache@users.noreply.github.com> Date: Tue, 6 Aug 2024 22:53:49 +0300 Subject: [PATCH 24/41] [NXP] Update k32w0 folder structure (#34772) * [platform][common] Add old nxp/k32w/common files Moving these files here since they are used by multiple platforms. K32W1 will be updated in the future and the old nxp/k32w/common will be removed. Keep it for now (duplicated files) to ease the synchronization of changes. Signed-off-by: marius-alex-tache * [NXP][k32w0] Remove k32w parent folder - examples/*/nxp/k32w/k32w0 becomes examples/*/nxp/k32w0 - src/platform/nxp/k32w/k32w0 becomes src/platform/nxp/k32w0 - third_party/openthread/platforms/nxp/k32w/k32w0 becomes third_party/openthread/platforms/nxp/k32w0 Signed-off-by: marius-alex-tache * [NXP][common][k32w0] Update some files after k32w parent removal Signed-off-by: marius-alex-tache (cherry picked from commit 039c51d1731de3acc583da906583d8fc0f482b8d) * [NXP][examples][k32w0] Remove examples/platform/nxp/k32w0 folder except docs examples/platform/nxp/k32w0/doc will remain in Matter repo. The other folders were moved to nxp_matter_support submodule. Signed-off-by: marius-alex-tache * [NXP][doc][k32w0] Updating path to update_nxp_sdk.py script Signed-off-by: Gatien Chapon (cherry picked from commit c729b5c6f8ac3b21345482d5f1585d1df1032770) * [NXP][examples][k32w0] Update paths after nxp_matter_support switch Signed-off-by: marius-alex-tache (cherry picked from commit 871ea893b3ad1f7d6d7b6943827a666b89f50b8f) * [NXP][examples][k32w0] Enable chip_generate_link_map_file by default Signed-off-by: marius-alex-tache * [NXP][examples][k32w0] Add OTA encryption info in contact sensor README Signed-off-by: marius-alex-tache * [NXP][docs] Fix spellcheck errors Signed-off-by: marius-alex-tache * [NXP] Bump nxp_matter_support repo Signed-off-by: marius-alex-tache * [k32w0][doc] Remove obsolete python dependency --------- Signed-off-by: marius-alex-tache Co-authored-by: Mihai Ignat --- .restyled.yaml | 1 - BUILD.gn | 6 +- config/k32w/toolchain/BUILD.gn | 8 +- docs/QUICK_START.md | 8 +- docs/guides/nxp/nxp_k32w0_ota_guide.md | 232 +++ .../nxp/nxp_k32w_android_commissioning.md | 37 +- .../nxp/k32w/k32w0/build_overrides | 1 - .../k32w/k32w0/third_party/connectedhomeip | 1 - .../nxp/{k32w => }/k32w0/.gn | 2 +- .../nxp/{k32w => }/k32w0/BUILD.gn | 29 +- .../nxp/{k32w => }/k32w0/README.md | 441 +++-- .../nxp/{k32w => }/k32w0/args.gni | 1 + .../nxp/k32w0/build_overrides | 1 + .../k32w0/include/CHIPProjectConfig.h | 4 +- .../{k32w => }/k32w0/include/FreeRTOSConfig.h | 0 .../nxp/{k32w => }/k32w0/main/AppTask.cpp | 21 +- .../k32w0/main/ContactSensorManager.cpp | 0 .../{k32w => }/k32w0/main/ZclCallbacks.cpp | 0 .../{k32w => }/k32w0/main/include/AppEvent.h | 0 .../{k32w => }/k32w0/main/include/AppTask.h | 5 +- .../k32w0/main/include/ContactSensorManager.h | 0 .../k32w0/main/include/app_config.h | 0 .../nxp/{k32w => }/k32w0/main/main.cpp | 2 +- .../nxp/k32w0/third_party/connectedhomeip | 1 + .../nxp/k32w/k32w0/build_overrides | 1 - .../k32w/k32w0/third_party/connectedhomeip | 1 - .../lighting-app/nxp/{k32w => }/k32w0/.gn | 2 +- .../nxp/{k32w => }/k32w0/BUILD.gn | 36 +- .../nxp/{k32w => }/k32w0/README.md | 377 +++-- .../nxp/{k32w => }/k32w0/args.gni | 1 + .../lighting-app/nxp/k32w0/build_overrides | 1 + .../k32w0/include/CHIPProjectConfig.h | 6 +- .../{k32w => }/k32w0/include/FreeRTOSConfig.h | 0 .../nxp/{k32w => }/k32w0/main/AppTask.cpp | 11 +- .../{k32w => }/k32w0/main/LightingManager.cpp | 0 .../{k32w => }/k32w0/main/ZclCallbacks.cpp | 0 .../{k32w => }/k32w0/main/include/AppEvent.h | 0 .../{k32w => }/k32w0/main/include/AppTask.h | 5 +- .../k32w0/main/include/LightingManager.h | 0 .../k32w0/main/include/app_config.h | 0 .../nxp/{k32w => }/k32w0/main/main.cpp | 2 +- .../nxp/k32w0/third_party/connectedhomeip | 1 + examples/platform/nxp/k32w/k32w0/BUILD.gn | 35 - examples/platform/nxp/k32w/k32w0/app/BUILD.gn | 27 - examples/platform/nxp/k32w/k32w0/app/args.gni | 28 - .../k32w0/app/ldscripts/chip-k32w0x-linker.ld | 448 ----- .../app/project_include/OpenThreadConfig.h | 116 -- .../nxp/k32w/k32w0/app/support/BUILD.gn | 52 - .../k32w/k32w0/app/support/FreeRtosHooks.c | 274 ---- .../k32w/k32w0/app/support/FreeRtosHooks.h | 42 - .../nxp/k32w/k32w0/app/support/Memconfig.cpp | 184 --- examples/platform/nxp/k32w/k32w0/args.gni | 32 - .../common/CustomFactoryDataProvider.cpp | 51 - .../k32w0/common/CustomFactoryDataProvider.h | 51 - .../nxp/k32w/k32w0/doc/images/ssbl_bin.JPG | Bin 45572 -> 0 bytes .../k32w0/doc/images/ssbl_multi_image.JPG | Bin 114896 -> 0 bytes .../nxp/k32w/k32w0/doc/images/ssbl_select.JPG | Bin 107428 -> 0 bytes .../k32w0/doc/images/ssbl_simple_hash.JPG | Bin 56397 -> 0 bytes .../demo_factory_data_dut1.bin | Bin 1161 -> 0 bytes .../demo_factory_data_dut2.bin | Bin 1161 -> 0 bytes .../nxp/k32w/k32w0/scripts/detokenizer.py | 148 -- .../nxp/k32w/k32w0/scripts/sign-outdir.py | 37 - .../nxp/k32w/k32w0/util/LEDWidget.cpp | 86 - .../nxp/k32w/k32w0/util/include/LEDWidget.h | 41 - .../doc/CustomFactoryDataProvider.md} | 0 .../k32w0/doc/images/chiptool_main_screen.png | Bin .../k32w0/doc/images/flash_location.JPG | Bin .../{k32w => }/k32w0/doc/images/form_web.JPG | Bin .../k32w0/doc/images/k32w-dk6-connectors.jpg | Bin .../{k32w => }/k32w0/doc/images/k32w-dk6.jpg | Bin .../{k32w => }/k32w0/doc/images/k32w-se.jpg | Bin .../k32w0/doc/images/mcux-sdk-download.JPG | Bin .../k32w0/doc/images/nxp_hw_connectivity.JPG | Bin .../k32w0/doc/images/on_off_cluster.png | Bin .../k32w0/doc/images/ota_topology.JPG | Bin .../k32w0/doc/images/pdm_ext_flash.JPG | Bin .../k32w0/doc/images/power_conf.JPG | Bin .../k32w0/doc/images/power_view.JPG | Bin .../k32w0/doc/images/select-sdk.JPG | Bin .../k32w0/doc/images/thread_credentials.png | Bin gn_build.sh | 2 +- scripts/build/builders/nxp.py | 2 +- scripts/setup/requirements.nxp.txt | 1 - .../nxp/common/legacy/BLEManagerCommon.cpp | 1435 +++++++++++++++++ .../nxp/common/legacy/BLEManagerCommon.h | 249 +++ .../nxp/common/legacy/FactoryDataDriver.cpp | 76 + .../nxp/common/legacy/FactoryDataDriver.h | 113 ++ .../nxp/common/legacy/FactoryDataProvider.cpp | 442 +++++ .../nxp/common/legacy/FactoryDataProvider.h | 177 ++ .../common/legacy/OTAFactoryDataProcessor.cpp | 165 ++ .../common/legacy/OTAFactoryDataProcessor.h | 78 + .../common/legacy/OTAImageProcessorImpl.cpp | 424 +++++ .../nxp/common/legacy/OTAImageProcessorImpl.h | 114 ++ .../nxp/common/legacy/OTATlvProcessor.cpp | 178 ++ .../nxp/common/legacy/OTATlvProcessor.h | 180 +++ src/platform/nxp/common/legacy/OTA_README.md | 149 ++ .../k32w0/DefaultTestEventTriggerDelegate.cpp | 31 - .../k32w0/DefaultTestEventTriggerDelegate.h | 36 - .../nxp/{k32w => }/k32w0/BLEManagerImpl.cpp | 2 +- .../nxp/{k32w => }/k32w0/BLEManagerImpl.h | 2 +- src/platform/nxp/{k32w => }/k32w0/BUILD.gn | 40 +- .../nxp/{k32w => }/k32w0/BlePlatformConfig.h | 0 .../k32w0/CHIPDevicePlatformConfig.h | 10 +- .../k32w0/CHIPDevicePlatformEvent.h | 0 .../CHIPDevicePlatformRamStorageConfig.h | 185 +++ .../nxp/{k32w => }/k32w0/CHIPPlatformConfig.h | 0 .../k32w0/ConfigurationManagerImpl.cpp | 4 +- .../k32w0/ConfigurationManagerImpl.h | 2 +- .../k32w0/ConnectivityManagerImpl.cpp | 0 .../k32w0/ConnectivityManagerImpl.h | 0 .../k32w0/DiagnosticDataProviderImpl.cpp | 2 +- .../k32w0/DiagnosticDataProviderImpl.h | 0 .../nxp/k32w0/FactoryDataProvider.cpp | 368 +++++ src/platform/nxp/k32w0/FactoryDataProvider.h | 158 ++ .../k32w0/FactoryDataProviderImpl.cpp | 12 +- .../k32w0/FactoryDataProviderImpl.h | 6 +- .../nxp/{k32w => }/k32w0/InetPlatformConfig.h | 0 .../nxp/{k32w => }/k32w0/K32W0Config.cpp | 2 +- .../nxp/{k32w => }/k32w0/K32W0Config.h | 2 +- .../k32w0/KeyValueStoreManagerImpl.cpp | 21 +- .../k32w0/KeyValueStoreManagerImpl.h | 4 +- src/platform/nxp/{k32w => }/k32w0/Logging.cpp | 0 .../nxp/{k32w => }/k32w0/LowPowerHooks.cpp | 0 .../nxp/{k32w => }/k32w0/NFCManagerImpl.cpp | 0 .../nxp/{k32w => }/k32w0/NFCManagerImpl.h | 0 .../k32w0/OTAFactoryDataProcessor.cpp | 7 +- .../k32w0/OTAFactoryDataProcessor.h | 6 +- .../{k32w => }/k32w0/OTAFirmwareProcessor.cpp | 6 +- .../{k32w => }/k32w0/OTAFirmwareProcessor.h | 2 +- .../nxp/{k32w => }/k32w0/OTAHooks.cpp | 20 +- .../{k32w => }/k32w0/PlatformManagerImpl.cpp | 4 +- .../{k32w => }/k32w0/PlatformManagerImpl.h | 0 .../nxp/{k32w => }/k32w0/RamStorage.cpp | 2 +- .../nxp/{k32w => }/k32w0/RamStorage.h | 0 .../{k32w => }/k32w0/SystemPlatformConfig.h | 0 .../{k32w => }/k32w0/SystemTimeSupport.cpp | 0 .../k32w0/ThreadStackManagerImpl.cpp | 0 .../{k32w => }/k32w0/ThreadStackManagerImpl.h | 0 src/platform/nxp/{k32w => }/k32w0/args.gni | 9 +- .../nxp/{k32w => }/k32w0/ble_function_mux.c | 0 .../nxp/{k32w => }/k32w0/ble_function_mux.h | 0 .../crypto/CHIPCryptoPALNXPUltrafastP256.cpp | 0 src/platform/nxp/{k32w => }/k32w0/gatt_db.h | 0 .../nxp/{k32w => }/k32w0/gatt_uuid128.h | 0 .../k32w0/k32w0-chip-mbedtls-config.h | 0 third_party/nxp/nxp_matter_support | 2 +- .../platforms/nxp/{k32w => }/k32w0/BUILD.gn | 8 +- 147 files changed, 5306 insertions(+), 2329 deletions(-) create mode 100644 docs/guides/nxp/nxp_k32w0_ota_guide.md delete mode 120000 examples/contact-sensor-app/nxp/k32w/k32w0/build_overrides delete mode 120000 examples/contact-sensor-app/nxp/k32w/k32w0/third_party/connectedhomeip rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/.gn (93%) rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/BUILD.gn (90%) rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/README.md (72%) rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/args.gni (97%) create mode 120000 examples/contact-sensor-app/nxp/k32w0/build_overrides rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/include/CHIPProjectConfig.h (98%) rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/include/FreeRTOSConfig.h (100%) rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/main/AppTask.cpp (96%) rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/main/ContactSensorManager.cpp (100%) rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/main/ZclCallbacks.cpp (100%) rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/main/include/AppEvent.h (100%) rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/main/include/AppTask.h (95%) rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/main/include/ContactSensorManager.h (100%) rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/main/include/app_config.h (100%) rename examples/contact-sensor-app/nxp/{k32w => }/k32w0/main/main.cpp (98%) create mode 120000 examples/contact-sensor-app/nxp/k32w0/third_party/connectedhomeip delete mode 120000 examples/lighting-app/nxp/k32w/k32w0/build_overrides delete mode 120000 examples/lighting-app/nxp/k32w/k32w0/third_party/connectedhomeip rename examples/lighting-app/nxp/{k32w => }/k32w0/.gn (94%) rename examples/lighting-app/nxp/{k32w => }/k32w0/BUILD.gn (87%) rename examples/lighting-app/nxp/{k32w => }/k32w0/README.md (73%) rename examples/lighting-app/nxp/{k32w => }/k32w0/args.gni (96%) create mode 120000 examples/lighting-app/nxp/k32w0/build_overrides rename examples/lighting-app/nxp/{k32w => }/k32w0/include/CHIPProjectConfig.h (97%) rename examples/lighting-app/nxp/{k32w => }/k32w0/include/FreeRTOSConfig.h (100%) rename examples/lighting-app/nxp/{k32w => }/k32w0/main/AppTask.cpp (98%) rename examples/lighting-app/nxp/{k32w => }/k32w0/main/LightingManager.cpp (100%) rename examples/lighting-app/nxp/{k32w => }/k32w0/main/ZclCallbacks.cpp (100%) rename examples/lighting-app/nxp/{k32w => }/k32w0/main/include/AppEvent.h (100%) rename examples/lighting-app/nxp/{k32w => }/k32w0/main/include/AppTask.h (95%) rename examples/lighting-app/nxp/{k32w => }/k32w0/main/include/LightingManager.h (100%) rename examples/lighting-app/nxp/{k32w => }/k32w0/main/include/app_config.h (100%) rename examples/lighting-app/nxp/{k32w => }/k32w0/main/main.cpp (97%) create mode 120000 examples/lighting-app/nxp/k32w0/third_party/connectedhomeip delete mode 100644 examples/platform/nxp/k32w/k32w0/BUILD.gn delete mode 100644 examples/platform/nxp/k32w/k32w0/app/BUILD.gn delete mode 100644 examples/platform/nxp/k32w/k32w0/app/args.gni delete mode 100644 examples/platform/nxp/k32w/k32w0/app/ldscripts/chip-k32w0x-linker.ld delete mode 100644 examples/platform/nxp/k32w/k32w0/app/project_include/OpenThreadConfig.h delete mode 100644 examples/platform/nxp/k32w/k32w0/app/support/BUILD.gn delete mode 100644 examples/platform/nxp/k32w/k32w0/app/support/FreeRtosHooks.c delete mode 100644 examples/platform/nxp/k32w/k32w0/app/support/FreeRtosHooks.h delete mode 100644 examples/platform/nxp/k32w/k32w0/app/support/Memconfig.cpp delete mode 100644 examples/platform/nxp/k32w/k32w0/args.gni delete mode 100644 examples/platform/nxp/k32w/k32w0/common/CustomFactoryDataProvider.cpp delete mode 100644 examples/platform/nxp/k32w/k32w0/common/CustomFactoryDataProvider.h delete mode 100644 examples/platform/nxp/k32w/k32w0/doc/images/ssbl_bin.JPG delete mode 100644 examples/platform/nxp/k32w/k32w0/doc/images/ssbl_multi_image.JPG delete mode 100644 examples/platform/nxp/k32w/k32w0/doc/images/ssbl_select.JPG delete mode 100755 examples/platform/nxp/k32w/k32w0/doc/images/ssbl_simple_hash.JPG delete mode 100644 examples/platform/nxp/k32w/k32w0/scripts/demo_generated_factory_data/demo_factory_data_dut1.bin delete mode 100644 examples/platform/nxp/k32w/k32w0/scripts/demo_generated_factory_data/demo_factory_data_dut2.bin delete mode 100644 examples/platform/nxp/k32w/k32w0/scripts/detokenizer.py delete mode 100644 examples/platform/nxp/k32w/k32w0/scripts/sign-outdir.py delete mode 100644 examples/platform/nxp/k32w/k32w0/util/LEDWidget.cpp delete mode 100644 examples/platform/nxp/k32w/k32w0/util/include/LEDWidget.h rename examples/platform/nxp/{k32w/k32w0/common/README.md => k32w0/doc/CustomFactoryDataProvider.md} (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/chiptool_main_screen.png (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/flash_location.JPG (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/form_web.JPG (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/k32w-dk6-connectors.jpg (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/k32w-dk6.jpg (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/k32w-se.jpg (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/mcux-sdk-download.JPG (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/nxp_hw_connectivity.JPG (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/on_off_cluster.png (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/ota_topology.JPG (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/pdm_ext_flash.JPG (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/power_conf.JPG (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/power_view.JPG (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/select-sdk.JPG (100%) rename examples/platform/nxp/{k32w => }/k32w0/doc/images/thread_credentials.png (100%) create mode 100644 src/platform/nxp/common/legacy/BLEManagerCommon.cpp create mode 100644 src/platform/nxp/common/legacy/BLEManagerCommon.h create mode 100644 src/platform/nxp/common/legacy/FactoryDataDriver.cpp create mode 100644 src/platform/nxp/common/legacy/FactoryDataDriver.h create mode 100644 src/platform/nxp/common/legacy/FactoryDataProvider.cpp create mode 100644 src/platform/nxp/common/legacy/FactoryDataProvider.h create mode 100644 src/platform/nxp/common/legacy/OTAFactoryDataProcessor.cpp create mode 100644 src/platform/nxp/common/legacy/OTAFactoryDataProcessor.h create mode 100644 src/platform/nxp/common/legacy/OTAImageProcessorImpl.cpp create mode 100644 src/platform/nxp/common/legacy/OTAImageProcessorImpl.h create mode 100644 src/platform/nxp/common/legacy/OTATlvProcessor.cpp create mode 100644 src/platform/nxp/common/legacy/OTATlvProcessor.h create mode 100644 src/platform/nxp/common/legacy/OTA_README.md delete mode 100644 src/platform/nxp/k32w/k32w0/DefaultTestEventTriggerDelegate.cpp delete mode 100644 src/platform/nxp/k32w/k32w0/DefaultTestEventTriggerDelegate.h rename src/platform/nxp/{k32w => }/k32w0/BLEManagerImpl.cpp (98%) rename src/platform/nxp/{k32w => }/k32w0/BLEManagerImpl.h (97%) rename src/platform/nxp/{k32w => }/k32w0/BUILD.gn (77%) rename src/platform/nxp/{k32w => }/k32w0/BlePlatformConfig.h (100%) rename src/platform/nxp/{k32w => }/k32w0/CHIPDevicePlatformConfig.h (97%) rename src/platform/nxp/{k32w => }/k32w0/CHIPDevicePlatformEvent.h (100%) create mode 100644 src/platform/nxp/k32w0/CHIPDevicePlatformRamStorageConfig.h rename src/platform/nxp/{k32w => }/k32w0/CHIPPlatformConfig.h (100%) rename src/platform/nxp/{k32w => }/k32w0/ConfigurationManagerImpl.cpp (98%) rename src/platform/nxp/{k32w => }/k32w0/ConfigurationManagerImpl.h (98%) rename src/platform/nxp/{k32w => }/k32w0/ConnectivityManagerImpl.cpp (100%) rename src/platform/nxp/{k32w => }/k32w0/ConnectivityManagerImpl.h (100%) rename src/platform/nxp/{k32w => }/k32w0/DiagnosticDataProviderImpl.cpp (99%) rename src/platform/nxp/{k32w => }/k32w0/DiagnosticDataProviderImpl.h (100%) create mode 100644 src/platform/nxp/k32w0/FactoryDataProvider.cpp create mode 100644 src/platform/nxp/k32w0/FactoryDataProvider.h rename src/platform/nxp/{k32w => }/k32w0/FactoryDataProviderImpl.cpp (94%) rename src/platform/nxp/{k32w => }/k32w0/FactoryDataProviderImpl.h (88%) rename src/platform/nxp/{k32w => }/k32w0/InetPlatformConfig.h (100%) rename src/platform/nxp/{k32w => }/k32w0/K32W0Config.cpp (99%) rename src/platform/nxp/{k32w => }/k32w0/K32W0Config.h (98%) rename src/platform/nxp/{k32w => }/k32w0/KeyValueStoreManagerImpl.cpp (93%) rename src/platform/nxp/{k32w => }/k32w0/KeyValueStoreManagerImpl.h (95%) rename src/platform/nxp/{k32w => }/k32w0/Logging.cpp (100%) rename src/platform/nxp/{k32w => }/k32w0/LowPowerHooks.cpp (100%) rename src/platform/nxp/{k32w => }/k32w0/NFCManagerImpl.cpp (100%) rename src/platform/nxp/{k32w => }/k32w0/NFCManagerImpl.h (100%) rename src/platform/nxp/{k32w => }/k32w0/OTAFactoryDataProcessor.cpp (97%) rename src/platform/nxp/{k32w => }/k32w0/OTAFactoryDataProcessor.h (93%) rename src/platform/nxp/{k32w => }/k32w0/OTAFirmwareProcessor.cpp (96%) rename src/platform/nxp/{k32w => }/k32w0/OTAFirmwareProcessor.h (96%) rename src/platform/nxp/{k32w => }/k32w0/OTAHooks.cpp (87%) rename src/platform/nxp/{k32w => }/k32w0/PlatformManagerImpl.cpp (98%) rename src/platform/nxp/{k32w => }/k32w0/PlatformManagerImpl.h (100%) rename src/platform/nxp/{k32w => }/k32w0/RamStorage.cpp (99%) rename src/platform/nxp/{k32w => }/k32w0/RamStorage.h (100%) rename src/platform/nxp/{k32w => }/k32w0/SystemPlatformConfig.h (100%) rename src/platform/nxp/{k32w => }/k32w0/SystemTimeSupport.cpp (100%) rename src/platform/nxp/{k32w => }/k32w0/ThreadStackManagerImpl.cpp (100%) rename src/platform/nxp/{k32w => }/k32w0/ThreadStackManagerImpl.h (100%) rename src/platform/nxp/{k32w => }/k32w0/args.gni (89%) rename src/platform/nxp/{k32w => }/k32w0/ble_function_mux.c (100%) rename src/platform/nxp/{k32w => }/k32w0/ble_function_mux.h (100%) rename src/platform/nxp/{k32w => }/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp (100%) rename src/platform/nxp/{k32w => }/k32w0/gatt_db.h (100%) rename src/platform/nxp/{k32w => }/k32w0/gatt_uuid128.h (100%) rename src/platform/nxp/{k32w => }/k32w0/k32w0-chip-mbedtls-config.h (100%) rename third_party/openthread/platforms/nxp/{k32w => }/k32w0/BUILD.gn (92%) diff --git a/.restyled.yaml b/.restyled.yaml index f55a0e367d91bd..c201729d30e41a 100644 --- a/.restyled.yaml +++ b/.restyled.yaml @@ -72,7 +72,6 @@ exclude: - "scripts/tools/zap/tests/outputs/**/*" # Matches generated output 1:1 - "examples/chef/sample_app_util/test_files/*.yaml" - "examples/chef/zzz_generated/**/*" - - "examples/platform/nxp/k32w/k32w0/scripts/demo_generated_certs/**/*" - "examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/zap-generated/*" # zap-generated files - "integrations/cloudbuild/*.yaml" # uglier long command line content - "scripts/run_codegen_targets.sh" # shellharden breaks for loops over command outputs diff --git a/BUILD.gn b/BUILD.gn index 82c8d855bfd291..8a78d8f55f3bd0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -689,7 +689,7 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") { if (enable_k32w_lighting_app_build) { group("k32w_lighting_app") { - deps = [ "${chip_root}/examples/lighting-app/nxp/k32w/k32w0/(${chip_root}/config/k32w/toolchain:k32w_lighting_app)" ] + deps = [ "${chip_root}/examples/lighting-app/nxp/k32w0/(${chip_root}/config/k32w/toolchain:k32w_lighting_app)" ] } extra_build_deps += [ ":k32w_lighting_app" ] @@ -697,7 +697,7 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") { if (enable_k32w_lock_app_build) { group("k32w_lock_app") { - deps = [ "${chip_root}/examples/lock-app/nxp/k32w/k32w0/(${chip_root}/config/k32w/toolchain:k32w_lock_app)" ] + deps = [ "${chip_root}/examples/lock-app/nxp/k32w0/(${chip_root}/config/k32w/toolchain:k32w_lock_app)" ] } extra_build_deps += [ ":k32w_lock_app" ] @@ -705,7 +705,7 @@ if (current_toolchain != "${dir_pw_toolchain}/default:default") { if (enable_k32w_shell_app_build) { group("k32w_shell_app") { - deps = [ "${chip_root}/examples/shell/nxp/k32w/k32w0/(${chip_root}/config/k32w/toolchain:k32w_shell_app)" ] + deps = [ "${chip_root}/examples/shell/nxp/k32w0/(${chip_root}/config/k32w/toolchain:k32w_shell_app)" ] } extra_build_deps += [ ":k32w_shell_app" ] diff --git a/config/k32w/toolchain/BUILD.gn b/config/k32w/toolchain/BUILD.gn index f386bcd0cd4c97..5189a17eff5a67 100644 --- a/config/k32w/toolchain/BUILD.gn +++ b/config/k32w/toolchain/BUILD.gn @@ -20,27 +20,27 @@ import("${build_root}/toolchain/arm_gcc/arm_toolchain.gni") arm_toolchain("k32w_lighting_app") { toolchain_args = { current_os = "freertos" - import("${chip_root}/examples/lighting-app/nxp/k32w/k32w0/args.gni") + import("${chip_root}/examples/lighting-app/nxp/k32w0/args.gni") } } arm_toolchain("k32w_lock_app") { toolchain_args = { current_os = "freertos" - import("${chip_root}/examples/lock-app/nxp/k32w/k32w0/args.gni") + import("${chip_root}/examples/lock-app/nxp/k32w0/args.gni") } } arm_toolchain("k32w_contact_sensor_app") { toolchain_args = { current_os = "freertos" - import("${chip_root}/examples/contact-sensor-app/nxp/k32w/k32w0/args.gni") + import("${chip_root}/examples/contact-sensor-app/nxp/k32w0/args.gni") } } arm_toolchain("k32w_shell_app") { toolchain_args = { current_os = "freertos" - import("${chip_root}/examples/shell/nxp/k32w/k32w0/args.gni") + import("${chip_root}/examples/shell/nxp/k32w0/args.gni") } } diff --git a/docs/QUICK_START.md b/docs/QUICK_START.md index 10833e0c0c1ed7..d5d80703c5e61f 100644 --- a/docs/QUICK_START.md +++ b/docs/QUICK_START.md @@ -17,10 +17,10 @@ and platforms. Use one of the controllers listed above and then a Border Router and Node combination listed below. -|
Border Router
|
Node
| Description | -| -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [**ot-br**](https://openthread.io/guides/border-router/build)
Thread Border Router
  • RasPi
  • BeagleBone | **lighting-app**
  • [Nordic nRF5x](https://github.com/project-chip/connectedhomeip/tree/master/examples/lighting-app/nrfconnect/README.md)
  • [NXP K32W](https://github.com/project-chip/connectedhomeip/tree/master/examples/lighting-app/nxp/k32w/k32w0/README.md)
  • [Qorvo QPG6100](https://github.com/project-chip/connectedhomeip/tree/master/examples/lighting-app/qpg)
  • [Silicon Labs EFR32](https://github.com/project-chip/connectedhomeip/tree/master/examples/lighting-app/silabs/README.md) | The Lighting example is supported by many of the available Thread platforms. See the chip-tool controller instructions for how to actuate the light on/off cluster. | -| [**ot-br**](https://openthread.io/guides/border-router/build)
    Thread Border Router
  • RasPi
  • BeagleBone | **lock-app**
  • [Nordic nRF5x](https://github.com/project-chip/connectedhomeip/tree/master/examples/lock-app/nrfconnect/README.md)
  • [NXP K32W](https://github.com/project-chip/connectedhomeip/tree/master/examples/lock-app/nxp/k32w/k32w0/README.md)
  • [Qorvo QPG6100](https://github.com/project-chip/connectedhomeip/tree/master/examples/lock-app/qpg)
  • [Silicon Labs EFR32](https://github.com/project-chip/connectedhomeip/tree/master/examples/lock-app/efr32/README.md)
  • [TI CC13x2x7](https://github.com/project-chip/connectedhomeip/tree/master/examples/lock-app/cc13x2x7_26x2x7/README.md) | The Lock example is supported by many of the available Thread and Wi-Fi platforms. | +|
    Border Router
    |
    Node
    | Description | +| -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [**ot-br**](https://openthread.io/guides/border-router/build)
    Thread Border Router
  • RasPi
  • BeagleBone | **lighting-app**
  • [Nordic nRF5x](https://github.com/project-chip/connectedhomeip/tree/master/examples/lighting-app/nrfconnect/README.md)
  • [NXP K32W](https://github.com/project-chip/connectedhomeip/tree/master/examples/lighting-app/nxp/k32w0/README.md)
  • [Qorvo QPG6100](https://github.com/project-chip/connectedhomeip/tree/master/examples/lighting-app/qpg)
  • [Silicon Labs EFR32](https://github.com/project-chip/connectedhomeip/tree/master/examples/lighting-app/silabs/README.md) | The Lighting example is supported by many of the available Thread platforms. See the chip-tool controller instructions for how to actuate the light on/off cluster. | +| [**ot-br**](https://openthread.io/guides/border-router/build)
    Thread Border Router
  • RasPi
  • BeagleBone | **lock-app**
  • [Nordic nRF5x](https://github.com/project-chip/connectedhomeip/tree/master/examples/lock-app/nrfconnect/README.md)
  • [Qorvo QPG6100](https://github.com/project-chip/connectedhomeip/tree/master/examples/lock-app/qpg)
  • [Silicon Labs EFR32](https://github.com/project-chip/connectedhomeip/tree/master/examples/lock-app/efr32/README.md)
  • [TI CC13x2x7](https://github.com/project-chip/connectedhomeip/tree/master/examples/lock-app/cc13x2x7_26x2x7/README.md) | The Lock example is supported by many of the available Thread and Wi-Fi platforms. | ## Controllers diff --git a/docs/guides/nxp/nxp_k32w0_ota_guide.md b/docs/guides/nxp/nxp_k32w0_ota_guide.md new file mode 100644 index 00000000000000..147bfdf2ee97e4 --- /dev/null +++ b/docs/guides/nxp/nxp_k32w0_ota_guide.md @@ -0,0 +1,232 @@ +# NXP K32W0x1 OTA guide + +## The Secondary Stage Bootloader (SSBL) + +There are multiple SSBL binaries provided by the SDK: + +| description | github SDK path | package SDK path | +| ------------------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | +| Default SSBL | NA | `boards/k32w061dk6/wireless_examples/framework/ssbl/binary/ssbl.bin` | +| SSBL with PDM in external flash | `examples/k32w061dk6/wireless_examples/framework/ssbl/binary/ssbl_ext_flash_pdm_support.bin` | `boards/k32w061dk6/wireless_examples/framework/ssbl/binary/ssbl_ext_flash_pdm_support.bin` | + +The SSBL is also built alongside the reference application and it can be +configured according to the following table: + +| gn arg | default | description | +| --------------------------------- | --------------------------- | ---------------------------------------------------------------------------------------- | +| `ssbl_pdm_external_flash` | true | Enable/disable PDM in external flash | +| `ssbl_multi_image_support` | true | Enable/disable multi-image OTA feature | +| `ssbl_ota_entry_storage` | "OTACustomStorage_ExtFlash" | Configure custom OTA entry storage type | +| `ssbl_simple_hash_verification` | false | Enable/disable simple hash verification alternative to secure boot | +| `ssbl_optimize_spifi_flash` | false | Optimize `SPIFI` flash driver size | +| `ssbl_spifi_dual_mode` | false | Enable/disable `SPIFI` dual mode support (e.g. used by K32W041AM variant) | +| `ssbl_version` | 0 | Set SSBL version | +| `ssbl_use_redlib` | false | Enable/disable usage of `redlib` NXP library. If false, the build will use `newlib` nano | +| `ssbl_ota_data_in_external_flash` | false | Enable/disable OTA support for application with sections stored in external flash | + +## Simple hash verification + +When secure boot is not used, a simple hash can be appended at the end of the +image for integrity check. Applications should be built with +`chip_simple_hash_verification=1`. + +## Writing the SSBL + +Before writing the SSBL, it it recommanded to fully erase the internal flash. + +Using DK6Programmer utility from Windows: + +``` +DK6Programmer.exe -V 5 -P 1000000 -s -e Flash +``` + +Using `dk6prog` from `SPSDK`: + +``` +$ dk6prog listdev +This is an experimental utility. Use with caution! + +List of available devices: +DEVICE ID: DN038ZH3, VID: 0x403, PID: 0x6015, Serial number: DN038ZH3, Description: DK6 Carrier Board, Address: 9, Backend: Backend.PYFTDI +$ dk6prog -d DN038ZH3 erase 0 0x9de00 + +This is an experimental utility. Use with caution! + +Erasing memory [####################################] 100% +``` + +`chip-k32w0x-ssbl.bin` must be written at address 0 in the internal flash: + +Using DK6Programmer utility from Windows: + +``` +DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x00="chip-k32w0x-ssbl.bin" +``` + +Using `dk6prog` from `SPSDK`: + +``` +$ dk6prog -d DN038ZH3 write 0 ~/path/to/bin/chip-k32w0x-ssbl.bin + +This is an experimental utility. Use with caution! + +Writing memory [####################################] 100% +Written 7890 bytes to memory ID 0 at address 0x0 +``` + +### Writing the PSECT + +This is the list of all supported partitions: + +``` +0000000010000000 : SSBL partition + + 00000000 -----------> Start Address + 1000 ---------------> 0x0010 Number of 512-bytes pages + 00 -----------------> 0x00 Bootable flag + 00 -----------------> 0x00 Image type (0x00 = SSBL) + +00400000c9040101: Application partition + + 00400000 -----------> 0x00004000 Start Address + c904 ---------------> 0x04c9 Number of 512-bytes pages + 01 -----------------> 0x01 Bootable flag + 01 -----------------> 0x01 Image type (0x01 = Application) + +00000010800000fe: Ext Flash text partition + + 00000010 -----------> 0x10000000 Start Address (external flash) + 8000 ---------------> 0x0080 Number of 512-bytes pages + 00 -----------------> 0x00 Bootable flag + fe -----------------> 0xFE Image type (0xFE = Ext Flash text) + +00000110300200fc : OTA Image partition + + 00000110 -----------> 0x10010000 Start Address + 3002----------------> 0x0230 Number of 512-bytes pages + 00 -----------------> 0x00 Bootable flag + fc -----------------> 0xFC Image type (0xFC = OTA partition) + +00000510100000fd: NVM partition + + 00000510 -----------> 0x10050000 Start Address + 1000 ---------------> 0x0010 Number of 512-bytes pages + 00 -----------------> 0x00 Bootable flag + fd -----------------> 0xFD Image type (0xFD = NVM partition) +``` + +First, image directory 0 (SSBL partition) must be written: + +Using DK6Programmer utility from Windows: + +``` +DK6Programmer.exe -V5 -s -P 1000000 -w image_dir_0=0000000010000000 +``` + +Using `dk6prog` from `SPSDK`: + +``` +$ dk6prog -d DN038ZH3 write 0x160 [[0000000010000000]] 8 PSECT + +This is an experimental utility. Use with caution! + +Writing memory [####################################] 100% +Written 8 bytes to memory ID PSECT at address 0x160 +``` + +Here is the interpretation of the fields: + +``` +00000000 -> start address 0x00000000 +1000 -> size = 0x0010 pages of 512-bytes (= 8kB) +00 -> not bootable (only used by the SSBL to support SSBL update) +00 -> SSBL Image Type +``` + +Second, image directory 1 (application partition) must be written: + +Using DK6Programmer utility from Windows: + +``` +DK6Programmer.exe -V5 -s -P 1000000 -w image_dir_1=00400000C9040101 +``` + +Using `dk6prog` from `SPSDK`: + +``` +$ dk6prog -d DN038ZH3 write 0x168 [[00400000C9040101]] 8 PSECT + +This is an experimental utility. Use with caution! + +Writing memory [####################################] 100% +Written 8 bytes to memory ID PSECT at address 0x168 +``` + +Here is the interpretation of the fields: + +``` +00400000 -> start address 0x00004000 +C904 -> 0x4C9 pages of 512-bytes (= 612.5kB) +01 -> bootable flag +01 -> image type for the application +``` + +Please note the user can write additional partitions by writing +`image_dir_2/3/4` with the wanted configuration. In case of using the `SPSDK` +tool, the appropriate offset must be calculated + +## Removing SSBL Upgrade Region + +The example also offers the possibility to remove SSBL upgrade region, for +reserving more space for application level. + +A new flag `chip_reduce_ssbl_size` is introduced. In order to remove the SSBL +upgrade region, `chip_reduce_ssbl_size=true` must be provided to the build +system + +The programming method will change: + +- Writing image directory 1 should change to Using DK6Programmer utility from + Windows: + + ``` + DK6Programmer.exe -V5 -s -P 1000000 -w image_dir_1=00200000D9040101 + ``` + + Using `dk6prog` from `SPSDK`: + + ``` + $ dk6prog -d DN038ZH3 write 0x168 [[00200000D9040101]] 8 PSECT + + This is an experimental utility. Use with caution! + + Writing memory [####################################] 100% + Written 8 bytes to memory ID PSECT at address 0x168 + ``` + + Here is the interpretation of the fields: + + ``` + 00200000 -> start address 0x00002000 + D904 -> 0x4D9 pages of 512-bytes (= 620.5kB) + 01 -> bootable flag + 01 -> image type for the application + ``` + +- Matter application offset address should change to Using DK6Programmer + utility from Windows: + + ``` + DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x2000="chip-k32w0x-contact-example.bin" + ``` + + Using `dk6prog` from `SPSDK`: + + ``` + $ dk6prog -d DN038ZH3 write 0x2000 ~/path/to/bin/chip-k32w0x-contact-example.bin + + This is an experimental utility. Use with caution! + + Writing memory [####################################] 100% + Written 596450 bytes to memory ID 0 at address 0x2000 + ``` diff --git a/docs/guides/nxp/nxp_k32w_android_commissioning.md b/docs/guides/nxp/nxp_k32w_android_commissioning.md index 6d872f5f7ba268..a37d60f0f0ba4e 100644 --- a/docs/guides/nxp/nxp_k32w_android_commissioning.md +++ b/docs/guides/nxp/nxp_k32w_android_commissioning.md @@ -8,16 +8,17 @@ onto a CHIP-enabled Thread network.
    -- [Overview](#overview) -- [Requirements](#requirements) -- [Building and programming OpenThread RCP firmware](#building-and-programming-openthread-rcp-firmware) -- [Configuring PC as Thread Border Router](#configuring-pc-as-a-thread-border-router) -- [Building and programming NXP K32W Light Example Application](#building-and-programming-nxp-k32w-light-example-application) -- [Building and installing Android CHIPTool](#building-and-installing-android-chiptool) -- [Forming a Thread network on the Border Router](#forming-a-thread-network-on-the-border-router) -- [Preparing accessory device](#preparing-accessory-device) -- [Commissioning accessory device](#commissioning-accessory-device) -- [Sending CHIP commands](#sending-chip-commands) +- [Commissioning NXP K32W using Android CHIPTool](#commissioning-nxp-k32w-using-android-chiptool) + - [Overview](#overview) + - [Requirements](#requirements) + - [Building and programming OpenThread RCP firmware](#building-and-programming-openthread-rcp-firmware) + - [Configuring PC as a Thread Border Router](#configuring-pc-as-a-thread-border-router) + - [Building and programming NXP K32W Light Example Application](#building-and-programming-nxp-k32w-light-example-application) + - [Building and installing Android CHIPTool](#building-and-installing-android-chiptool) + - [Forming a Thread network on the Border Router](#forming-a-thread-network-on-the-border-router) + - [Preparing accessory device](#preparing-accessory-device) + - [Commissioning accessory device](#commissioning-accessory-device) + - [Sending CHIP commands](#sending-chip-commands)
    @@ -47,7 +48,7 @@ The following diagram shows the connectivity between network components required to allow communication between devices running the CHIPTool and Light applications: -![nxp_hw_connectivity](../../../examples/platform/nxp/k32w/k32w0/doc/images/nxp_hw_connectivity.JPG) +![nxp_hw_connectivity](../../../examples/platform/nxp/k32w0/doc/images/nxp_hw_connectivity.JPG)
    @@ -111,7 +112,7 @@ the RCP firmware onto an K32W061 DK6: This creates an RCP image in the `bin/ot-rcp` directory. 6. Program the RCP firmware using the official - [OpenThread Flash Instructions](https://github.com/openthread/openthread/blob/master/examples/platforms/k32w/k32w061/README.md#flash-binaries). + [OpenThread Flash Instructions](https://github.com/openthread/openthread/blob/master/examples/platforms/k32w061/README.md#flash-binaries). 7. Plug-in the K32W061 DK6 to the PC. @@ -348,7 +349,7 @@ To make your PC work as a Thread Border Router, complete the following tasks: ## Building and programming NXP K32W Light Example Application See -[NXP K32W Light Example Application README](../../../examples/lighting-app/nxp/k32w/k32w0/README.md) +[NXP K32W Light Example Application README](../../../examples/lighting-app/nxp/k32w0/README.md) to learn how to build and program the light example onto an K32W061 DK6.
    @@ -396,7 +397,7 @@ CHIPTool is now ready to be used for commissioning. 3. Navigate to the _Form_ tab then push the _Form_ button using the default parameters: - ![nxp_form_nwk](../../../examples/platform/nxp/k32w/k32w0/doc/images/form_web.JPG) + ![nxp_form_nwk](../../../examples/platform/nxp/k32w0/doc/images/form_web.JPG) 4. The message _Form operation is successful_ should be display after a few seconds. @@ -430,7 +431,7 @@ To prepare the accessory device for commissioning, complete the following steps: 1. Make sure that JP4 and JP7 jumpers are in leftmost position and a mini-USB cable is connected between the LPC connector and PC - ![nxp_connectors](../../../examples/platform/nxp/k32w/k32w0/doc/images/k32w-dk6-connectors.jpg) + ![nxp_connectors](../../../examples/platform/nxp/k32w0/doc/images/k32w-dk6-connectors.jpg) 2. Use a terminal emulator (e.g.: Putty) to connect to the UART console of the accessory device. Use a baudrate of 115200. @@ -466,14 +467,14 @@ section, complete the following steps: progress with scanning, connection, and pairing. At the end of this process, the Thread network settings screen appears. - ![chiptool_main_screen](../../../examples/platform/nxp/k32w/k32w0/doc/images/chiptool_main_screen.png) + ![chiptool_main_screen](../../../examples/platform/nxp/k32w0/doc/images/chiptool_main_screen.png) 6. In the Thread network settings screen, use the default settings and tap the _SAVE NETWORK_ button to send a Thread provisioning message to the accessory device. You will see the "Network provisioning completed" message when the accessory device successfully joins the Thread network. - ![chiptool_credentials](../../../examples/platform/nxp/k32w/k32w0/doc/images/thread_credentials.png) + ![chiptool_credentials](../../../examples/platform/nxp/k32w0/doc/images/thread_credentials.png)
    @@ -483,7 +484,7 @@ section, complete the following steps: the provisioning is completed successfully and you are connected to the device. - ![on_off_cluster.png](../../../examples/platform/nxp/k32w/k32w0/doc/images/on_off_cluster.png) + ![on_off_cluster.png](../../../examples/platform/nxp/k32w0/doc/images/on_off_cluster.png) 2. Verify that the text box on the screen is not empty and contains the IPv6 address of the accessory device. diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/build_overrides b/examples/contact-sensor-app/nxp/k32w/k32w0/build_overrides deleted file mode 120000 index ad07557834803a..00000000000000 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/build_overrides +++ /dev/null @@ -1 +0,0 @@ -../../../../build_overrides/ \ No newline at end of file diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/third_party/connectedhomeip b/examples/contact-sensor-app/nxp/k32w/k32w0/third_party/connectedhomeip deleted file mode 120000 index 305f2077ffe860..00000000000000 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/third_party/connectedhomeip +++ /dev/null @@ -1 +0,0 @@ -../../../../../.. \ No newline at end of file diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/.gn b/examples/contact-sensor-app/nxp/k32w0/.gn similarity index 93% rename from examples/contact-sensor-app/nxp/k32w/k32w0/.gn rename to examples/contact-sensor-app/nxp/k32w0/.gn index 363727423ce903..1f7e4941f8d9fc 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/.gn +++ b/examples/contact-sensor-app/nxp/k32w0/.gn @@ -27,5 +27,5 @@ default_args = { import("//args.gni") # Import default platform configs - import("${chip_root}/src/platform/nxp/k32w/k32w0/args.gni") + import("${chip_root}/src/platform/nxp/k32w0/args.gni") } diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/BUILD.gn b/examples/contact-sensor-app/nxp/k32w0/BUILD.gn similarity index 90% rename from examples/contact-sensor-app/nxp/k32w/k32w0/BUILD.gn rename to examples/contact-sensor-app/nxp/k32w0/BUILD.gn index b69897172a1e8d..c51b8787ea2922 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/BUILD.gn +++ b/examples/contact-sensor-app/nxp/k32w0/BUILD.gn @@ -41,7 +41,7 @@ if (chip_pw_tokenizer_logging) { assert(current_os == "freertos") -k32w0_platform_dir = "${chip_root}/examples/platform/nxp/k32w/k32w0" +k32w0_platform_dir = "${nxp_sdk_matter_support_root}/examples/platform/k32w0" k32w0_sdk("sdk") { sources = [ @@ -88,6 +88,7 @@ k32w0_executable("contact_sensor_app") { defines = [] sources = [ + "${k32w0_platform_dir}/util/DefaultTestEventTriggerDelegate.cpp", "${k32w0_platform_dir}/util/LEDWidget.cpp", "${k32w0_platform_dir}/util/include/LEDWidget.h", "main/AppTask.cpp", @@ -119,17 +120,12 @@ k32w0_executable("contact_sensor_app") { "${k32w0_platform_dir}/app/support:freertos_mbedtls_utils", ] - if (chip_openthread_ftd) { - deps += [ - "${chip_root}/third_party/openthread/repo:libopenthread-cli-ftd", - "${chip_root}/third_party/openthread/repo:libopenthread-ftd", - ] - } else { - deps += [ - "${chip_root}/third_party/openthread/repo:libopenthread-cli-mtd", - "${chip_root}/third_party/openthread/repo:libopenthread-mtd", - ] - } + defines += [ "CONNECTIVITY_MANAGER_THREAD_DEVICE_TYPE=ConnectivityManager::kThreadDeviceType_SleepyEndDevice" ] + + deps += [ + "${chip_root}/third_party/openthread/repo:libopenthread-cli-mtd", + "${chip_root}/third_party/openthread/repo:libopenthread-mtd", + ] #lit and sit are using different zap files if (chip_enable_icd_lit) { @@ -187,6 +183,11 @@ group("k32w0") { ":binsign", ":contact_sensor_app", ] + + if (chip_enable_ota_requestor) { + deps += [ "${k32w0_platform_dir}/ssbl:ssbl" ] + } + if (chip_pw_tokenizer_logging) { deps += [ ":contact_sensor_app.database" ] } @@ -201,6 +202,10 @@ action("binsign") { if (chip_simple_hash_verification == 1) { args = [ "--simple-hash" ] } + + if (chip_enable_ota_requestor) { + args = [ "--ota-enabled" ] + } } group("default") { diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/README.md b/examples/contact-sensor-app/nxp/k32w0/README.md similarity index 72% rename from examples/contact-sensor-app/nxp/k32w/k32w0/README.md rename to examples/contact-sensor-app/nxp/k32w0/README.md index ac418ecbd4aa77..305aa0b176af2a 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/README.md +++ b/examples/contact-sensor-app/nxp/k32w0/README.md @@ -30,6 +30,8 @@ network. - [Rotating device id](#rotating-device-id) - [Manufacturing data](#manufacturing-data) - [Flashing and debugging](#flashing-and-debugging) + - [Using DK6programmer](#using-dk6programmer) + - [Using MCUXpresso](#using-mcuxpresso) - [Pigweed tokenizer](#pigweed-tokenizer) - [Detokenizer script](#detokenizer-script) - [Notes](#notes) @@ -39,21 +41,14 @@ network. - [Tinycrypt ECC library](#tinycrypt-ecc-library) - [Building steps](#building-steps-1) - [OTA](#ota) - - [Writing the SSBL](#writing-the-ssbl) - - [Features](#features) - - [Multi image](#multi-image) - - [Simple hash verification](#simple-hash-verification) - - [Writing the PSECT](#writing-the-psect) - - [Writing the application](#writing-the-application) - [OTA Testing](#ota-testing) - - [Known issues ota](#known-issues-ota) + - [Known issues OTA](#known-issues-ota) - [Low power](#low-power) - [Known issues low power](#known-issues-low-power) - - [Removing SSBL Upgrade Region](#removing-ssbl-upgrade-region) ## Introduction -![K32W061 DK6](../../../../platform/nxp/k32w/k32w0/doc/images/k32w-dk6.jpg) +![K32W061 DK6](../../../platform/nxp/k32w0/doc/images/k32w-dk6.jpg) The K32W061 contact sensor example application provides a working demonstration of a connected contact sensor device, built using the Project CHIP codebase and @@ -83,7 +78,7 @@ Deployment of this firmware configuration requires the K32W061 board setups using the K32W061 module board, SE051 Expansion board and Generic Expansion board as shown below: -![SE051H + K32W061 DK6](../../../../platform/nxp/k32w/k32w0/doc/images/k32w-se.jpg) +![SE051H + K32W061 DK6](../../../platform/nxp/k32w0/doc/images/k32w-se.jpg) The SE051H Secure Element extension may be used for best in class security and offloading some of the Project CHIP cryptographic operations. Depending on your @@ -186,10 +181,10 @@ contact status. In order to build the Project CHIP example, we recommend using a Linux distribution (supported Operating Systems are listed in -[BUILDING.md](../../../../../docs/guides/BUILDING.md#tested-operating systems)). +[BUILDING.md](../../../../docs/guides/BUILDING.md#tested-operating-systems)). - Make sure that below prerequisites are correctly installed (as described in - [BUILDING.md](../../../../../docs/guides/BUILDING.md#prerequisites))) + [BUILDING.md](../../../../docs/guides/BUILDING.md#prerequisites)) ``` sudo apt-get install git gcc g++ pkg-config libssl-dev libdbus-1-dev \ @@ -219,18 +214,18 @@ user@ubuntu:~/Desktop/git/connectedhomeip$ source scripts/bootstrap.sh - Step 3: Init NXP SDK(s) ``` -user@ubuntu:~/Desktop/git/connectedhomeip$ scripts/setup/nxp/update_nxp_sdk.py --platform k32w0 +user@ubuntu:~/Desktop/git/connectedhomeip$ third_party/nxp/nxp_matter_support/scripts/update_nxp_sdk.py --platform k32w0 ``` -Note: By default setup/nxp/update_nxp_sdk.py will try to initialize all NXP -SDKs. Arg "-- help" could be used to view all available options. +Note: By default update_nxp_sdk.py will try to initialize all NXP SDKs. Arg "-- +help" could be used to view all available options. - Start building the application: ```bash -user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/contact-sensor-app/nxp/k32w/k32w0 -user@ubuntu:~/Desktop/git/connectedhomeip/examples/contact-sensor-app/nxp/k32w/k32w0$ gn gen out/debug -user@ubuntu:~/Desktop/git/connectedhomeip/examples/contact-sensor-app/nxp/k32w/k32w0$ ninja -C out/debug +user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/contact-sensor-app/nxp/k32w0 +user@ubuntu:~/Desktop/git/connectedhomeip/examples/contact-sensor-app/nxp/k32w0$ gn gen out/debug +user@ubuntu:~/Desktop/git/connectedhomeip/examples/contact-sensor-app/nxp/k32w0$ ninja -C out/debug ``` To build with Secure Element, follow the same steps as above but set @@ -267,7 +262,7 @@ used to control an antenna switch. In order to use this feature, user must set In case signing errors are encountered when running the "sign_images.sh" script (run automatically) install the recommanded packages (python version > 3, pip3, -pycrypto, pycryptodome): +pycryptodome): ``` user@ubuntu:~$ python3 --version @@ -275,7 +270,6 @@ Python 3.8.2 user@ubuntu:~$ pip3 --version pip 20.0.2 from /usr/lib/python3/dist-packages/pip (python 3.8) user@ubuntu:~$ pip3 list | grep -i pycrypto -pycrypto 2.6.1 pycryptodome 3.9.8 ``` @@ -357,20 +351,20 @@ Please use the following build args: ## Manufacturing data See -[Guide for writing manufacturing data on NXP devices](../../../../../docs/guides/nxp/nxp_manufacturing_flow.md). +[Guide for writing manufacturing data on NXP devices](../../../../docs/guides/nxp/nxp_manufacturing_flow.md). There are factory data generated binaries available in -examples/platform/nxp/k32w/k32w0/scripts/demo_generated_factory_data folder. -These are based on the DAC, PAI and PAA certificates found in +`third_party/nxp/nxp_matter_support/examples/platform/k32w0/scripts/demo_generated_factory_data` +folder. These are based on the DAC, PAI and PAA certificates found in scripts/tools/nxp/demo_generated_certs folder. The demo_factory_data_dut1.bin uses the DAC certificate and private key found in -examples/platform/nxp/k32w/k32w0/scripts/demo_generated_factory_data/dac/dut1 +`third_party/nxp/nxp_matter_support/examples/platform/k32w0/scripts/demo_generated_factory_data/dac/dut1` folder. The demo_factory_data_dut2.bin uses the DAC certificate and private key found in -examples/platform/nxp/k32w/k32w0/scripts/demo_generated_factory_data/dac/dut2 +`third_party/nxp/nxp_matter_support/examples/platform/k32w0/scripts/demo_generated_factory_data/dac/dut2` folder. These two factory data binaries can be used for testing topologies with 2 DUTS. They contain the corresponding DACs/PAIs generated using -generate_nxp_chip_factory_bin.py script. The discriminator is 14014 and the +`generate_nxp_chip_factory_bin.py` script. The discriminator is 14014 and the passcode is 1000. These demo certificates are working with the CDs installed in CHIPProjectConfig.h. @@ -379,18 +373,140 @@ Regarding factory data provider, there are two options: - use the default factory data provider: `FactoryDataProviderImpl` by setting `chip_with_factory_data=1` in the gn build command. - use a custom factory data provider: please see - [Guide for implementing a custom factory data provider](../../../../platform/nxp/k32w/k32w0/common/README.md). + [Guide for implementing a custom factory data provider](../../../platform/nxp/k32w0/doc/CustomFactoryDataProvider.md). This can be enabled when `chip_with_factory_data=1` by setting `use_custom_factory_provider=1` in the gn build command. ## Flashing and debugging -Program the firmware using the official +Instructions to program the firmware can be found also at [OpenThread Flash Instructions](https://github.com/openthread/ot-nxp/tree/main/src/k32w0/k32w061#flash-binaries). -All you have to do is to replace the Openthread binaries from the above -documentation with _out/debug/chip-k32w0x-contact-example.bin_ if DK6Programmer -is used or with _out/debug/chip-k32w0x-contact-example_ if MCUXpresso is used. +### Using DK6programmer + +The application binary's path is _out/debug/chip-k32w0x-contact-example.bin_. + +DK6Programmer can be used for flashing the application. There are two available +versions of the DK6Programmer tool. + +The legacy version consists of a Windows executable found inside the +[SDK](https://mcuxpresso.nxp.com/en/welcome) at path +`tools/JN-SW-4407-DK6-Flash-Programmer`. This is a Windows application that can +be installed using the .exe file. Once the application is installed, the COM +port for K32W061 must be identified: + +``` +C:\nxp\DK6ProductionFlashProgrammer>DK6Programmer.exe --list +Available connections: + +``` + +Once the COM port is identified, the required binary can be flashed: + +``` +DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x4000="chip-k32w0x-contact-example.bin" +``` + +> **_Note:_** The above example takes into account that the binary uses the +> `chip_enable_ota_requestor=true` option. The address offset corresponds to the +> space left for the SSBL binary and the OTA space for the SSBL. If +> `chip_enable_ota_requestor` is set to `false`, then `0x4000` needs to be +> replaced with `0x0`. + +DK6 Flash Programmer tool has also been integrated part of +[NXP Secure Provisioning SDK (SPSDK)](https://github.com/nxp-mcuxpresso/spsdk). +This tool is supported by environments like Windows, Linux or Mac. + +`SPSDK` can be installed and run from a Python environment using +[these instructions](https://spsdk.readthedocs.io/en/latest/usage/installation.html). +This enables the user to have transparent access to the dk6 programming tool +through `SPSDK`. + +``` +# after specific environment installation steps +$ spsdk --help +... + +-- dk6prog Tool for reading and programming flash memory of DK6 target devices. + � +-- erase Erase the memory. + � +-- info Prints the information about the connected device. + � +-- isp Issues ISP sequence as defined in Driver interface. + � +-- listdev Prints the information about the connected devices. + � +-- read Reads the memory and writes it to the file or stdout. + � +-- write Write the memory. +... +``` + +Dependencies for the `dk6prog` module can be installed using the following +command, more details +[here](https://spsdk.readthedocs.io/en/latest/usage/installation.html#dk6-tools): + +``` +$ pip install spsdk[dk6] +``` + +The `SPSDK` installation adds `dk6prog` as executable to system path, so user +can use directly `dk6prog` from terminal. The following commands are to be used +to write the chip-k32w0x-contact-example binary to the board. + +``` +$ dk6prog listdev +This is an experimental utility. Use with caution! + +List of available devices: +DEVICE ID: DN038ZH3, VID: 0x403, PID: 0x6015, Serial number: DN038ZH3, Description: DK6 Carrier Board, Address: 9, Backend: Backend.PYFTDI +$ dk6prog -d DN038ZH3 write 0x4000 ~/path/to/bin/chip-k32w0x-contact-example.bin + +This is an experimental utility. Use with caution! + +Writing memory [####################################] 100% +Written 596450 bytes to memory ID 0 at address 0x4000 +``` + +> **_Note:_** Running `dk6prog` from Windows OS command line requires an integer +> value for DEVICE ID. + +``` +C:\nxp\spsdk>dk6prog listdev + +This is an experimental utility. Use with caution! + +List of available devices: +DEVICE ID: 0, VID: 0x0, PID: 0x0, Serial number: b'DN038ZH3', Description: b'DK6 Carrier Board', Address: 67330069, Backend: Backend.FTD2xx + +C:\nxp\spsdk>dk6prog -d 0 info + +This is an experimental utility. Use with caution! + +Chip ID: 0x88888888 +ROM Version: 0x140000cc +MAC Address: A8:2B:1F:03:00:8D:15:00 + +Detected DEVICE: UNKNOWN + + Memory Memory ID Base Address Length Sector Size Memory Type Access +---------------------------------------------------------------------------------------------- + FLASH 0 0x0 0x9de00 0x200 FLASH All is available + PSECT 1 0x0 0x1e0 0x10 FLASH All is available + pFLASH 2 0x0 0x1e0 0x10 FLASH All is available + Config 3 0x9fc00 0x200 0x200 FLASH All is available + EFUSE 4 0x0 0x80 0x2 EFUSE (OTP) Write Enabled + ROM 5 0x3000000 0x20000 0x1 ROM Write Enabled + RAM0 6 0x4000000 0x16000 0x1 RAM Write Enabled + RAM1 7 0x4020000 0x10000 0x1 RAM Write Enabled +``` + +> **_Note:_** The above example takes into account that the binary uses the +> `chip_enable_ota_requestor=true` option. The address offset corresponds to the +> space left for the SSBL binary and the OTA space for the SSBL. If +> `chip_enable_ota_requestor` is set to `false`, then `0x4000` needs to be +> replaced with `0x0`. + +### Using MCUXpresso + +If flashing and debugging is required, MCUXpresso can be used as instructed in +[MCUXpresso flashing and debugging instructions](https://github.com/openthread/ot-nxp/tree/main/src/k32w0/k32w061#using-mcuxpresso-ide). +The file needed to be used in MCUXpresso is +_out/debug/chip-k32w0x-contact-example_. ## Pigweed tokenizer @@ -403,7 +519,7 @@ needed for parsing the hashed scripts. The python3 script detokenizer.py is a script that decodes the tokenized logs either from a file or from a serial port. It is located in the following path -`examples/platform/nxp/k32w/k32w0/scripts/detokenizer.py`. +`third_party/nxp/nxp_matter_support/examples/platform/k32w0/scripts/detokenizer.py`. The script can be used in the following ways: @@ -438,7 +554,7 @@ by the script is loaded by the environment. An example of running the detokenizer script to see logs of a contact-sensor app: ``` -python3 ../../../../../examples/platform/nxp/k32w/k32w0/scripts/detokenizer.py serial -i /dev/ttyACM0 -d out/debug/chip-k32w0x-contact-example-database.bin -o device.txt +python3 ../../../../third_party/nxp/nxp_matter_support/examples/platform/k32w0/scripts/detokenizer.py serial -i /dev/ttyACM0 -d out/debug/chip-k32w0x-contact-example-database.bin -o device.txt ``` ### Known issues tokenizer @@ -483,179 +599,49 @@ In order to use the Tinycrypt ECC library, use the following build arguments: ## OTA -The internal flash needs to be prepared for the OTA process. First 16K of the -internal flash needs to be populated with a Secondary Stage Bootloader (SSBL) -related data while the last 8.5K of flash space is holding image directory -related data (PSECT). The space between these two zones will be filled by the +Over the air updates (OTA) require several software components running on the +K32W0x1. Firstly, a Secondary Stage Bootloader (SSBL) is required written in the +first part of the internal flash memory, usually starting at address 0x0. This +enables the board to boot and check if a new OTA binary has been received. If +this is true, the bootloader writes the OTA binary to the appropriate storage, +internal and/or external flash, after which it reboots the board. If no new OTA +binaries have been found, then the bootloader gives execution control to the application. -### Writing the SSBL - -The SDK already provides an SSBL binary compiled with external flash support: -`boards/k32w061dk6/wireless_examples/framework/ssbl/binary/ssbl_ext_flash_pdm_support.bin`, -but it does not offer multi-image OTA support. - -Alternatively, the SSBL can ge generated from one of the SDK demo examples. The -SSBL demo application can be imported from the `Quickstart panel`: -`Import SDK example(s) -> select wireless -> framework -> ssbl` application. - -![SSBL Application Select](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_select.JPG) - -### Features - -#### Multi image - -To support multi-image OTA feature, the SSBL project must be compiled using the -following defines: - -- `PDM_EXT_FLASH=1` - support PDM in external flash. -- `gOTAUseCustomOtaEntry=1` - support custom OTA entry for multi-image. -- `gOTACustomOtaEntryMemory=OTACustomStorage_ExtFlash` - K32W0 uses - `OTACustomStorage_ExtFlash` (1) by default. -- `SPIFI_DUAL_MODE_SUPPORT=1` - only for configurations that use dual `SPIFI` - flash (e.g. K32W041AM variant). - -Optionally, add the following defines: - -- `SPIFI_OPTIM_SIZE=1` - to optimize SSBL size. -- `EXTERNAL_FLASH_DATA_OTA=1` - to support external read only data. - -![SSBL_MULTI_IMAGE](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_multi_image.JPG) - -#### Simple hash verification - -When secure boot is not used, a simple hash can be appended at the end of the -image for integrity check. Applications should be built with -`chip_simple_hash_verification=1`. - -To support simple hash verification feature, the SSBL project must be compiled -with: - -- `gSimpleHashVerification=1` - -and update the post-build command to use simple hash verification instead of the -default options. Go to -`Project -> Properties -> C/C++ Build -> Settings -> Build steps` and press -`Edit` under `Post-build steps` subsection. The command should look similar to: - -![SSBL_SIMPLE_HASH_VERIFICATION](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_simple_hash.JPG) - -Once compiled, the required SSBL file is called `k32w061dk6_ssbl.bin`. - -![SSBL_BIN](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_bin.JPG) - -Before writing the SSBL, it it recommanded to fully erase the internal flash: - -``` -DK6Programmer.exe -V 5 -P 1000000 -s -e Flash -``` - -`k32w061dk6_ssbl.bin` must be written at address 0 in the internal flash: - -``` -DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x00="k32w061dk6_ssbl.bin" -``` - -### Writing the PSECT - -This is the list of all supported partitions: - -``` -0000000010000000 : SSBL partition - - 00000000 -----------> Start Address - 1000 ---------------> 0x0010 Number of 512-bytes pages - 00 -----------------> 0x00 Bootable flag - 00 -----------------> 0x00 Image type (0x00 = SSBL) - -00400000c9040101: Application partition - - 00400000 -----------> 0x00004000 Start Address - c904 ---------------> 0x04c9 Number of 512-bytes pages - 01 -----------------> 0x01 Bootable flag - 01 -----------------> 0x01 Image type (0x01 = Application) - -00000010800000fe: Ext Flash text partition - - 00000010 -----------> 0x10000000 Start Address (external flash) - 8000 ---------------> 0x0080 Number of 512-bytes pages - 00 -----------------> 0x00 Bootable flag - fe -----------------> 0xFE Image type (0xFE = Ext Flash text) - -00000110300200fc : OTA Image partition - - 00000110 -----------> 0x10010000 Start Address - 3002----------------> 0x0230 Number of 512-bytes pages - 00 -----------------> 0x00 Bootable flag - fc -----------------> 0xFC Image type (0xFC = OTA partition) - -00000510100000fd: NVM partition - - 00000510 -----------> 0x10050000 Start Address - 1000 ---------------> 0x0010 Number of 512-bytes pages - 00 -----------------> 0x00 Bootable flag - fd -----------------> 0xFD Image type (0xFD = NVM partition) -``` - -First, image directory 0 (SSBL partition) must be written: - -``` -DK6Programmer.exe -V5 -s -P 1000000 -w image_dir_0=0000000010000000 -``` - -Here is the interpretation of the fields: - -``` -00000000 -> start address 0x00000000 -1000 -> size = 0x0010 pages of 512-bytes (= 8kB) -00 -> not bootable (only used by the SSBL to support SSBL update) -00 -> SSBL Image Type -``` - -Second, image directory 1 (application partition) must be written: - -``` -DK6Programmer.exe -V5 -s -P 1000000 -w image_dir_1=00400000C9040101 -``` - -Here is the interpretation of the fields: - -``` -00400000 -> start address 0x00004000 -C904 -> 0x4C9 pages of 512-bytes (= 612.5kB) -01 -> bootable flag -01 -> image type for the application -``` - -Please note the user can write additional partitions by writing -`image_dir_2/3/4` with the wanted configuration. - -### Writing the application +The internal flash needs to be prepared for the OTA process. First 16K of the +internal flash needs to be populated with SSBL related data while the last 8.5K +of flash space is holding flash configuration related data. The space between +these two zones will be filled by the application. More details regarding the +internal flash space can be found in the +[linker file](../../../../third_party/nxp/nxp_matter_support/examples/platform/k32w0/app/ldscripts/chip-k32w0x-linker.ld). -DK6Programmer can be used for flashing the application: +The steps for building the SSBL binary with appropriate configuration and +writing to the board the binary and other OTA related configurations are +described in the +[K32W0x1 OTA guide](../../../../docs/guides/nxp/nxp_k32w0_ota_guide.md). -``` -DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x4000="chip-k32w0x-contact-example.bin" -``` +Note that the application needs to be built using the +`chip_enable_ota_requestor=true` option. This is enabled in the configuration by +default if no `chip_enable_ota_requestor` explicit setting is done. -If debugging is needed, MCUXpresso can be used then for flashing the -application. Please make sure that the application is written at address 0x4000: - -![FLASH_LOCATION](../../../../platform/nxp/k32w/k32w0/doc/images/flash_location.JPG) +Please also note that, by default, the device expects the OTA image to be +encrypted with the same key specified by `chip_with_ota_key`. See `args.gni` for +the default gn configuration. ### OTA Testing The OTA topology used for OTA testing is illustrated in the figure below. Topology is similar with the one used for Matter Test Events. -![OTA_TOPOLOGY](../../../../platform/nxp/k32w/k32w0/doc/images/ota_topology.JPG) +![OTA_TOPOLOGY](../../../platform/nxp/k32w0/doc/images/ota_topology.JPG) The concept for OTA is the next one: - there is an OTA Provider Application that holds the OTA image. In our case, this is a Linux application running on an Ubuntu based-system; -- the OTA Requestor functionality is embedded inside the Lighting Application. - It will be used for requesting OTA blocks from the OTA Provider; +- the OTA Requestor functionality is embedded inside the Contact Sensor + Application. It will be used for requesting OTA blocks from the OTA + Provider; - the controller (a linux application called chip-tool) will be used for commissioning both the device and the OTA Provider App. The device will be commissioned using the standard Matter flow (BLE + IEEE 802.15.4) while the @@ -663,19 +649,19 @@ The concept for OTA is the next one: of chip-tool; - during commissioning, each device is assigned a node id by the chip-tool (can be specified manually by the user). Using the node id of the device and - of the lighting application, chip-tool triggers the OTA transfer by invoking - the _announce-ota-provider_ command - basically, the OTA Requestor is - informed of the node id of the OTA Provider Application. + of the contact sensor application, chip-tool triggers the OTA transfer by + invoking the _announce-ota-provider_ command - basically, the OTA Requestor + is informed of the node id of the OTA Provider Application. _Computer #1_ can be any system running an Ubuntu distribution. We recommand -using TE 7.5 instructions from -[here](https://groups.csa-iot.org/wg/matter-csg/document/24839), where RPi 4 are -proposed. Also, TE 7.5 instructions document point to the OS/Docker images that -should be used on the RPis. For compatibility reasons, we recommand compiling -chip-tool and OTA Provider applications with the same commit id that was used -for compiling the Lighting Application. Also, please note that there is a single -controller (chip-tool) running on Computer #1 which is used for commissioning -both the device and the OTA Provider Application. If needed, +using CSA official instructions from +[here](https://groups.csa-iot.org/wg/matter-csg/document/28566), where RPi 4 are +proposed. Also, CSA official instructions document point to the OS/Docker images +that should be used on the RPis. For compatibility reasons, we recommand +compiling chip-tool and OTA Provider applications with the same commit id that +was used for compiling the Contact Sensor Application. Also, please note that +there is a single controller (chip-tool) running on Computer #1 which is used +for commissioning both the device and the OTA Provider Application. If needed, [these instructions](https://itsfoss.com/connect-wifi-terminal-ubuntu/) could be used for connecting the RPis to WiFi. @@ -696,7 +682,7 @@ Build OTA image: In order to build an OTA image, use NXP wrapper over the standard tool `src/app/ota_image_tool.py`: -- `scripts/tools/nxp/ota/ota_image_tool.py`. +- `scripts/tools/nxp/ota/ota_image_tool.py` The tool can be used to generate an OTA image with the following format: @@ -725,7 +711,7 @@ The address for storing the custom OTA entry can also be specified: address that does not overlap with anything else. Please see more in the -[OTA image tool guide](../../../../../scripts/tools/nxp/ota/README.md). +[OTA image tool guide](../../../../scripts/tools/nxp/ota/README.md). Here is an example that generates an OTA image with application update TLV: @@ -735,16 +721,16 @@ Here is an example that generates an OTA image with application update TLV: Please note the two options `--enc_enable` and `--input_ota_key`, which are mandatory when `chip_with_ota_encryption=1`. The value of `--input_ota_key` must -match the value of `chip_with_ota_key`. See `args.gni` for the default gn -configuration. +match the value of `chip_with_ota_key`. A note regarding OTA image header version (`-vn` option). An application binary has its own software version, given by -`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION` (`42020` by default), which can be +`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION` (`1` by default), which can be overwritten. For having a correct OTA process, the OTA header version should be -the same as the binary embedded software version. A user can set a custom -software version in the gn build args by setting `chip_software_version` to the -wanted version. +the same as the binary embedded software version. When building the update +image, the build arguments `nxp_software_version=2` and +`nxp_sofware_version_string=\"2.0\"` can be added to the gn gen command in order +to specify the upgraded version. Start the OTA Provider Application: @@ -774,7 +760,7 @@ Start the OTA process: user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool otasoftwareupdaterequestor announce-otaprovider 1 0 0 0 2 0 ``` -### Known issues ota +### Known issues OTA - SRP cache on the openthread border router needs to flushed each time a new commissioning process is attempted. For this, factory reset the device, then @@ -827,13 +813,13 @@ Power Measurement Tool can be used inside MCUXpresso for checking the power consumption pattern: Window -> Show View -> Other -> Power Measurement Tool. The configuration for this tool is the next one: -![POWER_CONF](../../../../platform/nxp/k32w/k32w0/doc/images/power_conf.JPG) +![POWER_CONF](../../../platform/nxp/k32w0/doc/images/power_conf.JPG) Also, please make sure that the J14 jumper is set to the _ENABLED_ position and no expansion board is attached to the DK6. A view from this tool is illustrated below: -![POWER_VIEW](../../../../platform/nxp/k32w/k32w0/doc/images/power_view.JPG) +![POWER_VIEW](../../../platform/nxp/k32w0/doc/images/power_view.JPG) Please note that that the Power Measurement Tool is not very accurate and professional tools must be used if exact power consumption needs to be known. @@ -842,34 +828,3 @@ professional tools must be used if exact power consumption needs to be known. - Power Measurement Tool may not work correctly in MCUXpresso versions greater that 11.0.1. - -## Removing SSBL Upgrade Region - -The example also offers the possibility to remove SSBL upgrade region, for -reserving more space for application level. - -A new flag `chip_reduce_ssbl_size` is introduced. In order to remove the SSBL -upgrade region, `chip_reduce_ssbl_size=true` must be provided to the build -system - -The programming method will change: - -- writing image directory 1 should change to - - ``` - DK6Programmer.exe -V5 -s -P 1000000 -w image_dir_1=00200000D9040101 - ``` - - Here is the interpretation of the fields: - - ``` - 00200000 -> start address 0x00002000 - D904 -> 0x4D9 pages of 512-bytes (= 620.5kB) - 01 -> bootable flag - 01 -> image type for the application - ``` - -- Matter application offset address should change to - ``` - DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x2000="chip-k32w0x-contact-example.bin" - ``` diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/args.gni b/examples/contact-sensor-app/nxp/k32w0/args.gni similarity index 97% rename from examples/contact-sensor-app/nxp/k32w/k32w0/args.gni rename to examples/contact-sensor-app/nxp/k32w0/args.gni index e328a6ede9011f..1709f1da735d5d 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/args.gni +++ b/examples/contact-sensor-app/nxp/k32w0/args.gni @@ -24,6 +24,7 @@ chip_with_ota_key = "1234567890ABCDEFA1B2C3D4E5F6F1B4" chip_stack_lock_tracking = "fatal" chip_enable_ble = true +chip_generate_link_map_file = true chip_enable_icd_server = true chip_enable_icd_lit = false diff --git a/examples/contact-sensor-app/nxp/k32w0/build_overrides b/examples/contact-sensor-app/nxp/k32w0/build_overrides new file mode 120000 index 00000000000000..ee19c065d619a2 --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w0/build_overrides @@ -0,0 +1 @@ +../../../build_overrides/ \ No newline at end of file diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h b/examples/contact-sensor-app/nxp/k32w0/include/CHIPProjectConfig.h similarity index 98% rename from examples/contact-sensor-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h rename to examples/contact-sensor-app/nxp/k32w0/include/CHIPProjectConfig.h index 301d53824a7e55..2b0afde85d56fe 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h +++ b/examples/contact-sensor-app/nxp/k32w0/include/CHIPProjectConfig.h @@ -145,11 +145,11 @@ * {MAJOR_VERSION}.0d{MINOR_VERSION} */ #ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING -#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "03-2022-te8" +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING NXP_CONFIG_DEVICE_SOFTWARE_VERSION_STRING #endif #ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION -#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 42020 +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION NXP_CONFIG_DEVICE_SOFTWARE_VERSION #endif #ifndef CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/include/FreeRTOSConfig.h b/examples/contact-sensor-app/nxp/k32w0/include/FreeRTOSConfig.h similarity index 100% rename from examples/contact-sensor-app/nxp/k32w/k32w0/include/FreeRTOSConfig.h rename to examples/contact-sensor-app/nxp/k32w0/include/FreeRTOSConfig.h diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/main/AppTask.cpp b/examples/contact-sensor-app/nxp/k32w0/main/AppTask.cpp similarity index 96% rename from examples/contact-sensor-app/nxp/k32w/k32w0/main/AppTask.cpp rename to examples/contact-sensor-app/nxp/k32w0/main/AppTask.cpp index d7d9763e491a62..d350a4527d281c 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/main/AppTask.cpp +++ b/examples/contact-sensor-app/nxp/k32w0/main/AppTask.cpp @@ -42,11 +42,12 @@ #include #include #include -#include +#include #endif -#include +#include +#include "DefaultTestEventTriggerDelegate.h" #include "Keyboard.h" #include "LED.h" #include "LEDWidget.h" @@ -94,6 +95,11 @@ static chip::DeviceLayer::CustomFactoryDataProvider sCustomFactoryDataProvider; #endif #endif +// This key is for testing/certification only and should not be used in production devices. +// For production devices this key must be provided from factory data. +uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + static Identify gIdentify = { chip::EndpointId{ 1 }, AppTask::OnIdentifyStart, AppTask::OnIdentifyStop, Clusters::Identify::IdentifyTypeEnum::kVisibleIndicator }; @@ -107,7 +113,7 @@ static BDXDownloader gDownloader; constexpr uint16_t requestedOtaBlockSize = 1024; #endif -#if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA && CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA && CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR CHIP_ERROR CustomFactoryDataRestoreMechanism(void) { K32W_LOG("This is a custom factory data restore mechanism."); @@ -154,7 +160,7 @@ static void CheckOtaEntry() if (ota_entries.ota_state == otaApplied) { K32W_LOG("OTA successfully applied"); -#if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA && CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA && CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR // If this point is reached, it means OTA_CommitCustomEntries was successfully called. // Delete the factory data backup to stop doing a restore when the factory data provider // is initialized. This ensures that both the factory data and app were updated, otherwise @@ -184,7 +190,7 @@ CHIP_ERROR AppTask::Init() if (ContactSensorMgr().Init() != 0) { K32W_LOG("ContactSensorMgr().Init() failed"); - assert(status == 0); + assert(0); } PlatformMgr().AddEventHandler(MatterEventHandler, 0); @@ -196,9 +202,8 @@ CHIP_ERROR AppTask::Init() CheckOtaEntry(); #endif - // Initialize device attestation config #if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA -#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR sFactoryDataProvider.RegisterRestoreMechanism(CustomFactoryDataRestoreMechanism); #endif ReturnErrorOnFailure(sFactoryDataProvider.Init()); @@ -299,6 +304,8 @@ void AppTask::InitServer(intptr_t arg) chip::DeviceLayer::SetDeviceInfoProvider(&infoProvider); // Init ZCL Data Model and start server + static DefaultTestEventTriggerDelegate sTestEventTriggerDelegate{ ByteSpan(sTestEventTriggerEnableKey) }; + initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate; chip::Inet::EndPointStateOpenThread::OpenThreadEndpointInitParam nativeParams; nativeParams.lockCb = LockOpenThreadTask; nativeParams.unlockCb = UnlockOpenThreadTask; diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/main/ContactSensorManager.cpp b/examples/contact-sensor-app/nxp/k32w0/main/ContactSensorManager.cpp similarity index 100% rename from examples/contact-sensor-app/nxp/k32w/k32w0/main/ContactSensorManager.cpp rename to examples/contact-sensor-app/nxp/k32w0/main/ContactSensorManager.cpp diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/main/ZclCallbacks.cpp b/examples/contact-sensor-app/nxp/k32w0/main/ZclCallbacks.cpp similarity index 100% rename from examples/contact-sensor-app/nxp/k32w/k32w0/main/ZclCallbacks.cpp rename to examples/contact-sensor-app/nxp/k32w0/main/ZclCallbacks.cpp diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/main/include/AppEvent.h b/examples/contact-sensor-app/nxp/k32w0/main/include/AppEvent.h similarity index 100% rename from examples/contact-sensor-app/nxp/k32w/k32w0/main/include/AppEvent.h rename to examples/contact-sensor-app/nxp/k32w0/main/include/AppEvent.h diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/main/include/AppTask.h b/examples/contact-sensor-app/nxp/k32w0/main/include/AppTask.h similarity index 95% rename from examples/contact-sensor-app/nxp/k32w/k32w0/main/include/AppTask.h rename to examples/contact-sensor-app/nxp/k32w0/main/include/AppTask.h index c3203d78eb543e..3f81915dca23f9 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/main/include/AppTask.h +++ b/examples/contact-sensor-app/nxp/k32w0/main/include/AppTask.h @@ -27,7 +27,7 @@ #include "CHIPProjectConfig.h" #if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA -#include +#include #if CHIP_DEVICE_CONFIG_USE_CUSTOM_PROVIDER #include "CustomFactoryDataProvider.h" #endif @@ -50,6 +50,9 @@ class AppTask { public: +#if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA + using FactoryDataProvider = chip::DeviceLayer::FactoryDataProviderImpl; +#endif CHIP_ERROR StartAppTask(); static void AppTaskMain(void * pvParameter); diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/main/include/ContactSensorManager.h b/examples/contact-sensor-app/nxp/k32w0/main/include/ContactSensorManager.h similarity index 100% rename from examples/contact-sensor-app/nxp/k32w/k32w0/main/include/ContactSensorManager.h rename to examples/contact-sensor-app/nxp/k32w0/main/include/ContactSensorManager.h diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/main/include/app_config.h b/examples/contact-sensor-app/nxp/k32w0/main/include/app_config.h similarity index 100% rename from examples/contact-sensor-app/nxp/k32w/k32w0/main/include/app_config.h rename to examples/contact-sensor-app/nxp/k32w0/main/include/app_config.h diff --git a/examples/contact-sensor-app/nxp/k32w/k32w0/main/main.cpp b/examples/contact-sensor-app/nxp/k32w0/main/main.cpp similarity index 98% rename from examples/contact-sensor-app/nxp/k32w/k32w0/main/main.cpp rename to examples/contact-sensor-app/nxp/k32w0/main/main.cpp index 56288842a3f5de..9517d7e2cf4309 100644 --- a/examples/contact-sensor-app/nxp/k32w/k32w0/main/main.cpp +++ b/examples/contact-sensor-app/nxp/k32w0/main/main.cpp @@ -154,7 +154,7 @@ extern "C" void main_task(void const * argument) */ sched_enable(); - err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_SleepyEndDevice); + err = ConnectivityMgr().SetThreadDeviceType(CONNECTIVITY_MANAGER_THREAD_DEVICE_TYPE); if (err != CHIP_NO_ERROR) { goto exit; diff --git a/examples/contact-sensor-app/nxp/k32w0/third_party/connectedhomeip b/examples/contact-sensor-app/nxp/k32w0/third_party/connectedhomeip new file mode 120000 index 00000000000000..3efed95be5dbe9 --- /dev/null +++ b/examples/contact-sensor-app/nxp/k32w0/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../../ \ No newline at end of file diff --git a/examples/lighting-app/nxp/k32w/k32w0/build_overrides b/examples/lighting-app/nxp/k32w/k32w0/build_overrides deleted file mode 120000 index ad07557834803a..00000000000000 --- a/examples/lighting-app/nxp/k32w/k32w0/build_overrides +++ /dev/null @@ -1 +0,0 @@ -../../../../build_overrides/ \ No newline at end of file diff --git a/examples/lighting-app/nxp/k32w/k32w0/third_party/connectedhomeip b/examples/lighting-app/nxp/k32w/k32w0/third_party/connectedhomeip deleted file mode 120000 index 305f2077ffe860..00000000000000 --- a/examples/lighting-app/nxp/k32w/k32w0/third_party/connectedhomeip +++ /dev/null @@ -1 +0,0 @@ -../../../../../.. \ No newline at end of file diff --git a/examples/lighting-app/nxp/k32w/k32w0/.gn b/examples/lighting-app/nxp/k32w0/.gn similarity index 94% rename from examples/lighting-app/nxp/k32w/k32w0/.gn rename to examples/lighting-app/nxp/k32w0/.gn index cfa8fcb8c07dc4..e0a89b885879e6 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/.gn +++ b/examples/lighting-app/nxp/k32w0/.gn @@ -31,5 +31,5 @@ default_args = { [ "${chip_root}/scripts/setup/requirements.build.txt" ] # Import default platform configs - import("${chip_root}/src/platform/nxp/k32w/k32w0/args.gni") + import("${chip_root}/src/platform/nxp/k32w0/args.gni") } diff --git a/examples/lighting-app/nxp/k32w/k32w0/BUILD.gn b/examples/lighting-app/nxp/k32w0/BUILD.gn similarity index 87% rename from examples/lighting-app/nxp/k32w/k32w0/BUILD.gn rename to examples/lighting-app/nxp/k32w0/BUILD.gn index 82afd7ad22864d..a63a5967c3948b 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/BUILD.gn +++ b/examples/lighting-app/nxp/k32w0/BUILD.gn @@ -40,7 +40,7 @@ if (chip_pw_tokenizer_logging) { assert(current_os == "freertos") -k32w0_platform_dir = "${chip_root}/examples/platform/nxp/k32w/k32w0" +k32w0_platform_dir = "${nxp_sdk_matter_support_root}/examples/platform/k32w0" k32w0_sdk("sdk") { sources = [ @@ -84,7 +84,10 @@ k32w0_sdk("sdk") { k32w0_executable("light_app") { output_name = "chip-k32w0x-light-example" + defines = [] + sources = [ + "${k32w0_platform_dir}/util/DefaultTestEventTriggerDelegate.cpp", "${k32w0_platform_dir}/util/LEDWidget.cpp", "${k32w0_platform_dir}/util/include/LEDWidget.h", "main/AppTask.cpp", @@ -96,15 +99,13 @@ k32w0_executable("light_app") { "main/main.cpp", ] - public = [ "${chip_root}/src/platform/nxp/k32w/k32w0/DefaultTestEventTriggerDelegate.h" ] - if (chip_with_factory_data == 1 && use_custom_factory_provider == 1) { sources += [ "${k32w0_platform_dir}/common/CustomFactoryDataProvider.cpp", "${k32w0_platform_dir}/common/CustomFactoryDataProvider.h", ] - defines = [ "CHIP_DEVICE_CONFIG_USE_CUSTOM_PROVIDER=1" ] + defines += [ "CHIP_DEVICE_CONFIG_USE_CUSTOM_PROVIDER=1" ] } deps = [ @@ -112,7 +113,6 @@ k32w0_executable("light_app") { "${chip_root}/examples/common/QRCode", "${chip_root}/examples/lighting-app/nxp/zap/", "${chip_root}/examples/providers:device_info_provider", - "${chip_root}/src/app:test-event-trigger", "${chip_root}/src/lib", "${chip_root}/src/platform:syscalls_stub", "${chip_root}/src/platform/logging:default", @@ -120,17 +120,12 @@ k32w0_executable("light_app") { "${k32w0_platform_dir}/app/support:freertos_mbedtls_utils", ] - if (chip_openthread_ftd) { - deps += [ - "${chip_root}/third_party/openthread/repo:libopenthread-cli-ftd", - "${chip_root}/third_party/openthread/repo:libopenthread-ftd", - ] - } else { - deps += [ - "${chip_root}/third_party/openthread/repo:libopenthread-cli-mtd", - "${chip_root}/third_party/openthread/repo:libopenthread-mtd", - ] - } + defines += [ "CONNECTIVITY_MANAGER_THREAD_DEVICE_TYPE=ConnectivityManager::kThreadDeviceType_MinimalEndDevice" ] + + deps += [ + "${chip_root}/third_party/openthread/repo:libopenthread-cli-mtd", + "${chip_root}/third_party/openthread/repo:libopenthread-mtd", + ] cflags = [ "-Wconversion" ] @@ -169,6 +164,11 @@ group("k32w0") { ":binsign", ":light_app", ] + + if (chip_enable_ota_requestor) { + deps += [ "${k32w0_platform_dir}/ssbl:ssbl" ] + } + if (chip_pw_tokenizer_logging) { deps += [ ":light_app.database" ] } @@ -183,6 +183,10 @@ action("binsign") { if (chip_simple_hash_verification == 1) { args = [ "--simple-hash" ] } + + if (chip_enable_ota_requestor) { + args = [ "--ota-enabled" ] + } } group("default") { diff --git a/examples/lighting-app/nxp/k32w/k32w0/README.md b/examples/lighting-app/nxp/k32w0/README.md similarity index 73% rename from examples/lighting-app/nxp/k32w/k32w0/README.md rename to examples/lighting-app/nxp/k32w0/README.md index a0f560e2e884c4..518e0232a4f6cb 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/README.md +++ b/examples/lighting-app/nxp/k32w0/README.md @@ -27,10 +27,12 @@ network. - [Identify cluster LED state](#identify-cluster-led-state) - [Building](#building) - [Overwrite board config files](#overwrite-board-config-files) - - [Known issues building](#known-issues-building) + - [Known issues building](#known-issues-building) - [Rotating device id](#rotating-device-id) - [Manufacturing data](#manufacturing-data) - [Flashing and debugging](#flashing-and-debugging) + - [Using DK6programmer](#using-dk6programmer) + - [Using MCUXpresso](#using-mcuxpresso) - [Pigweed tokenizer](#pigweed-tokenizer) - [Detokenizer script](#detokenizer-script) - [Notes](#notes) @@ -40,18 +42,12 @@ network. - [Tinycrypt ECC library](#tinycrypt-ecc-library) - [Building steps](#building-steps-1) - [OTA](#ota) - - [Writing the SSBL](#writing-the-ssbl) - - [Features](#features) - - [Multi image](#multi-image) - - [Simple hash verification](#simple-hash-verification) - - [Writing the PSECT](#writing-the-psect) - - [Writing the application](#writing-the-application) - [OTA Testing](#ota-testing) - - [Known issues ota](#known-issues-ota) + - [Known issues OTA](#known-issues-ota) ## Introduction -![K32W061 DK6](../../../../platform/nxp/k32w/k32w0/doc/images/k32w-dk6.jpg) +![K32W061 DK6](../../../platform/nxp/k32w0/doc/images/k32w-dk6.jpg) The K32W061 lighting example application provides a working demonstration of a light bulb device, built using the Project CHIP codebase and the NXP K32W061 @@ -81,7 +77,7 @@ Deployment of this firmware configuration requires the K32W061 board setups using the K32W061 module board, SE051 Expansion board and Generic Expansion board as shown below: -![SE051H + K32W061 DK6](../../../../platform/nxp/k32w/k32w0/doc/images/k32w-se.jpg) +![SE051H + K32W061 DK6](../../../platform/nxp/k32w0/doc/images/k32w-se.jpg) The SE051H Secure Element extension may be used for best in class security and offloading some of the Project CHIP cryptographic operations. Depending on your @@ -198,10 +194,10 @@ effects: In order to build the Project CHIP example, we recommend using a Linux distribution (supported Operating Systems are listed in -[BUILDING.md](../../../../../docs/guides/BUILDING.md#tested-operating systems)). +[BUILDING.md](../../../../docs/guides/BUILDING.md#tested-operating-systems)). - Make sure that below prerequisites are correctly installed (as described in - [BUILDING.md](../../../../../docs/guides/BUILDING.md#prerequisites))) + [BUILDING.md](../../../../docs/guides/BUILDING.md#prerequisites)) ``` sudo apt-get install git gcc g++ pkg-config libssl-dev libdbus-1-dev \ @@ -231,18 +227,18 @@ user@ubuntu:~/Desktop/git/connectedhomeip$ source scripts/bootstrap.sh - Step 3: Init NXP SDK(s) ``` -user@ubuntu:~/Desktop/git/connectedhomeip$ scripts/setup/nxp/update_nxp_sdk.py --platform k32w0 +user@ubuntu:~/Desktop/git/connectedhomeip$ third_party/nxp/nxp_matter_support/scripts/update_nxp_sdk.py --platform k32w0 ``` -Note: By default setup/nxp/update_nxp_sdk.py will try to initialize all NXP -SDKs. Arg "-- help" could be used to view all available options. +Note: By default update_nxp_sdk.py will try to initialize all NXP SDKs. Arg "-- +help" could be used to view all available options. - Start building the application: ```bash -user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/lighting-app/nxp/k32w/k32w0 -user@ubuntu:~/Desktop/git/connectedhomeip/examples/lighting-app/nxp/k32w/k32w0$ gn gen out/debug -user@ubuntu:~/Desktop/git/connectedhomeip/examples/lighting-app/nxp/k32w/k32w0$ ninja -C out/debug +user@ubuntu:~/Desktop/git/connectedhomeip$ cd examples/lighting-app/nxp/k32w0 +user@ubuntu:~/Desktop/git/connectedhomeip/examples/lighting-app/nxp/k32w0$ gn gen out/debug +user@ubuntu:~/Desktop/git/connectedhomeip/examples/lighting-app/nxp/k32w0$ ninja -C out/debug ``` To build with Secure Element, follow the same steps as above but set @@ -279,7 +275,7 @@ used to control an antenna switch. In order to use this feature, user must set In case signing errors are encountered when running the "sign_images.sh" script (run automatically) install the recommanded packages (python version > 3, pip3, -pycrypto, pycryptodome): +pycryptodome): ``` user@ubuntu:~$ python3 --version @@ -287,7 +283,6 @@ Python 3.8.2 user@ubuntu:~$ pip3 --version pip 20.0.2 from /usr/lib/python3/dist-packages/pip (python 3.8) user@ubuntu:~$ pip3 list | grep -i pycrypto -pycrypto 2.6.1 pycryptodome 3.9.8 ``` @@ -310,7 +305,7 @@ k32w0_sdk("sdk") { This variable will be used by `k32w0_sdk.gni` to overwrite `chip_with_DK6` option, thus the reference board configuration files will no longer be used. -## Known issues building +### Known issues building - When using Secure element and cross-compiling on Linux, log messages from the Plug&Trust middleware stack may not echo to the console. @@ -333,20 +328,20 @@ Please use the following build args: ## Manufacturing data See -[Guide for writing manufacturing data on NXP devices](../../../../../docs/guides/nxp/nxp_manufacturing_flow.md). +[Guide for writing manufacturing data on NXP devices](../../../../docs/guides/nxp/nxp_manufacturing_flow.md). There are factory data generated binaries available in -examples/platform/nxp/k32w/k32w0/scripts/demo_generated_factory_data folder. -These are based on the DAC, PAI and PAA certificates found in +`third_party/nxp/nxp_matter_support/examples/platform/k32w0/scripts/demo_generated_factory_data` +folder. These are based on the DAC, PAI and PAA certificates found in scripts/tools/nxp/demo_generated_certs folder. The demo_factory_data_dut1.bin uses the DAC certificate and private key found in -examples/platform/nxp/k32w/k32w0/scripts/demo_generated_factory_data/dac/dut1 +`third_party/nxp/nxp_matter_support/examples/platform/k32w0/scripts/demo_generated_factory_data/dac/dut1` folder. The demo_factory_data_dut2.bin uses the DAC certificate and private key found in -examples/platform/nxp/k32w/k32w0/scripts/demo_generated_factory_data/dac/dut2 +`third_party/nxp/nxp_matter_support/examples/platform/k32w0/scripts/demo_generated_factory_data/dac/dut2` folder. These two factory data binaries can be used for testing topologies with 2 DUTS. They contain the corresponding DACs/PAIs generated using -generate_nxp_chip_factory_bin.py script. The discriminator is 14014 and the +`generate_nxp_chip_factory_bin.py` script. The discriminator is 14014 and the passcode is 1000. These demo certificates are working with the CDs installed in CHIPProjectConfig.h. @@ -355,18 +350,140 @@ Regarding factory data provider, there are two options: - use the default factory data provider: `FactoryDataProviderImpl` by setting `chip_with_factory_data=1` in the gn build command. - use a custom factory data provider: please see - [Guide for implementing a custom factory data provider](../../../../platform/nxp/k32w/k32w0/common/README.md). + [Guide for implementing a custom factory data provider](../../../platform/nxp/k32w0/doc/CustomFactoryDataProvider.md). This can be enabled when `chip_with_factory_data=1` by setting `use_custom_factory_provider=1` in the gn build command. ## Flashing and debugging -Program the firmware using the official +Instructions to program the firmware can be found also at [OpenThread Flash Instructions](https://github.com/openthread/ot-nxp/tree/main/src/k32w0/k32w061#flash-binaries). -All you have to do is to replace the Openthread binaries from the above -documentation with _out/debug/chip-k32w0x-light-example.bin_ if DK6Programmer is -used or with _out/debug/chip-k32w0x-light-example_ if MCUXpresso is used. +### Using DK6programmer + +The application binary's path is _out/debug/chip-k32w0x-light-example.bin_. + +DK6Programmer can be used for flashing the application. There are two available +versions of the DK6Programmer tool. + +The legacy version consists of a Windows executable found inside the +[SDK](https://mcuxpresso.nxp.com/en/welcome) at path +`tools/JN-SW-4407-DK6-Flash-Programmer`. This is a Windows application that can +be installed using the .exe file. Once the application is installed, the COM +port for K32W061 must be identified: + +``` +C:\nxp\DK6ProductionFlashProgrammer>DK6Programmer.exe --list +Available connections: + +``` + +Once the COM port is identified, the required binary can be flashed: + +``` +DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x4000="chip-k32w0x-light-example.bin" +``` + +> **_Note:_** The above example takes into account that the binary uses the +> `chip_enable_ota_requestor=true` option. The address offset corresponds to the +> space left for the SSBL binary and the OTA space for the SSBL. If +> `chip_enable_ota_requestor` is set to `false`, then `0x4000` needs to be +> replaced with `0x0`. + +DK6 Flash Programmer tool has also been integrated part of +[NXP Secure Provisioning SDK (SPSDK)](https://github.com/nxp-mcuxpresso/spsdk). +This tool is supported by environments like Windows, Linux or Mac. + +`SPSDK` can be installed and run from a Python environment using +[these instructions](https://spsdk.readthedocs.io/en/latest/usage/installation.html). +This enables the user to have transparent access to the dk6 programming tool +through `SPSDK`. + +``` +# after specific environment installation steps +$ spsdk --help +... + +-- dk6prog Tool for reading and programming flash memory of DK6 target devices. + � +-- erase Erase the memory. + � +-- info Prints the information about the connected device. + � +-- isp Issues ISP sequence as defined in Driver interface. + � +-- listdev Prints the information about the connected devices. + � +-- read Reads the memory and writes it to the file or stdout. + � +-- write Write the memory. +... +``` + +Dependencies for the `dk6prog` module can be installed using the following +command, more details +[here](https://spsdk.readthedocs.io/en/latest/usage/installation.html#dk6-tools): + +``` +$ pip install spsdk[dk6] +``` + +The `SPSDK` installation adds `dk6prog` as executable to system path, so user +can use directly `dk6prog` from terminal. The following commands are to be used +to write the chip-k32w0x-light-example binary to the board. + +``` +$ dk6prog listdev +This is an experimental utility. Use with caution! + +List of available devices: +DEVICE ID: DN038ZH3, VID: 0x403, PID: 0x6015, Serial number: DN038ZH3, Description: DK6 Carrier Board, Address: 9, Backend: Backend.PYFTDI +$ dk6prog -d DN038ZH3 write 0x4000 ~/path/to/bin/chip-k32w0x-light-example.bin + +This is an experimental utility. Use with caution! + +Writing memory [####################################] 100% +Written 596450 bytes to memory ID 0 at address 0x4000 +``` + +> **_Note:_** Running `dk6prog` from Windows OS command line requires an integer +> value for DEVICE ID. + +``` +C:\nxp\spsdk>dk6prog listdev + +This is an experimental utility. Use with caution! + +List of available devices: +DEVICE ID: 0, VID: 0x0, PID: 0x0, Serial number: b'DN038ZH3', Description: b'DK6 Carrier Board', Address: 67330069, Backend: Backend.FTD2xx + +C:\nxp\spsdk>dk6prog -d 0 info + +This is an experimental utility. Use with caution! + +Chip ID: 0x88888888 +ROM Version: 0x140000cc +MAC Address: A8:2B:1F:03:00:8D:15:00 + +Detected DEVICE: UNKNOWN + + Memory Memory ID Base Address Length Sector Size Memory Type Access +---------------------------------------------------------------------------------------------- + FLASH 0 0x0 0x9de00 0x200 FLASH All is available + PSECT 1 0x0 0x1e0 0x10 FLASH All is available + pFLASH 2 0x0 0x1e0 0x10 FLASH All is available + Config 3 0x9fc00 0x200 0x200 FLASH All is available + EFUSE 4 0x0 0x80 0x2 EFUSE (OTP) Write Enabled + ROM 5 0x3000000 0x20000 0x1 ROM Write Enabled + RAM0 6 0x4000000 0x16000 0x1 RAM Write Enabled + RAM1 7 0x4020000 0x10000 0x1 RAM Write Enabled +``` + +> **_Note:_** The above example takes into account that the binary uses the +> `chip_enable_ota_requestor=true` option. The address offset corresponds to the +> space left for the SSBL binary and the OTA space for the SSBL. If +> `chip_enable_ota_requestor` is set to `false`, then `0x4000` needs to be +> replaced with `0x0`. + +### Using MCUXpresso + +If flashing and debugging is required, MCUXpresso can be used as instructed in +[MCUXpresso flashing and debugging instructions](https://github.com/openthread/ot-nxp/tree/main/src/k32w0/k32w061#using-mcuxpresso-ide). +The file needed to be used in MCUXpresso is +_out/debug/chip-k32w0x-light-example_. ## Pigweed tokenizer @@ -379,7 +496,7 @@ needed for parsing the hashed scripts. The python3 script detokenizer.py is a script that decodes the tokenized logs either from a file or from a serial port. It is located in the following path -`examples/platform/nxp/k32w/k32w0/scripts/detokenizer.py`. +`third_party/nxp/nxp_matter_support/examples/platform/k32w0/scripts/detokenizer.py`. The script can be used in the following ways: @@ -414,7 +531,7 @@ by the script is loaded by the environment. An example of running the detokenizer script to see logs of a lighting app: ``` -python3 ../../../../../examples/platform/nxp/k32w/k32w0/scripts/detokenizer.py serial -i /dev/ttyACM0 -d out/debug/chip-k32w0x-light-example-database.bin -o device.txt +python3 ../../../../third_party/nxp/nxp_matter_support/examples/platform/k32w0/scripts/detokenizer.py serial -i /dev/ttyACM0 -d out/debug/chip-k32w0x-light-example-database.bin -o device.txt ``` ### Known issues tokenizer @@ -459,172 +576,37 @@ In order to use the Tinycrypt ECC library, use the following build arguments: ## OTA -The internal flash needs to be prepared for the OTA process. First 16K of the -internal flash needs to be populated with a Secondary Stage Bootloader (SSBL) -related data while the last 8.5K of flash space is holding image directory -related data (PSECT). The space between these two zones will be filled by the +Over the air updates (OTA) require several software components running on the +K32W0x1. Firstly, a Secondary Stage Bootloader (SSBL) is required written in the +first part of the internal flash memory, usually starting at address 0x0. This +enables the board to boot and check if a new OTA binary has been received. If +this is true, the bootloader writes the OTA binary to the appropriate storage, +internal and/or external flash, after which it reboots the board. If no new OTA +binaries have been found, then the bootloader gives execution control to the application. -### Writing the SSBL - -The SDK already provides an SSBL binary compiled with external flash support: -`boards/k32w061dk6/wireless_examples/framework/ssbl/binary/ssbl_ext_flash_pdm_support.bin`, -but it does not offer multi-image OTA support. - -Alternatively, the SSBL can ge generated from one of the SDK demo examples. The -SSBL demo application can be imported from the `Quickstart panel`: -`Import SDK example(s) -> select wireless -> framework -> ssbl` application. - -![SSBL Application Select](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_select.JPG) - -### Features - -#### Multi image - -To support multi-image OTA feature, the SSBL project must be compiled using the -following defines: - -- `PDM_EXT_FLASH=1` - support PDM in external flash. -- `gOTAUseCustomOtaEntry=1` - support custom OTA entry for multi-image. -- `gOTACustomOtaEntryMemory=OTACustomStorage_ExtFlash` - K32W0 uses - `OTACustomStorage_ExtFlash` (1) by default. -- `SPIFI_DUAL_MODE_SUPPORT=1` - only for configurations that use dual `SPIFI` - flash (e.g. K32W041AM variant). - -Optionally, add the following defines: - -- `SPIFI_OPTIM_SIZE=1` - to optimize SSBL size. -- `EXTERNAL_FLASH_DATA_OTA=1` - to support external read only data. - -![SSBL_MULTI_IMAGE](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_multi_image.JPG) - -#### Simple hash verification - -When secure boot is not used, a simple hash can be appended at the end of the -image for integrity check. Applications should be built with -`chip_simple_hash_verification=1`. - -To support simple hash verification feature, the SSBL project must be compiled -with: - -- `gSimpleHashVerification=1` - -and update the post-build command to use simple hash verification instead of the -default options. Go to -`Project -> Properties -> C/C++ Build -> Settings -> Build steps` and press -`Edit` under `Post-build steps` subsection. The command should look similar to: - -![SSBL_SIMPLE_HASH_VERIFICATION](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_simple_hash.JPG) - -Once compiled, the required SSBL file is called `k32w061dk6_ssbl.bin`. - -![SSBL_BIN](../../../../platform/nxp/k32w/k32w0/doc/images/ssbl_bin.JPG) - -Before writing the SSBL, it it recommanded to fully erase the internal flash: - -``` -DK6Programmer.exe -V 5 -P 1000000 -s -e Flash -``` - -`k32w061dk6_ssbl.bin` must be written at address 0 in the internal flash: - -``` -DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x00="k32w061dk6_ssbl.bin" -``` - -### Writing the PSECT - -This is the list of all supported partitions: - -``` -0000000010000000 : SSBL partition - - 00000000 -----------> Start Address - 1000 ---------------> 0x0010 Number of 512-bytes pages - 00 -----------------> 0x00 Bootable flag - 00 -----------------> 0x00 Image type (0x00 = SSBL) - -00400000c9040101: Application partition - - 00400000 -----------> 0x00004000 Start Address - c904 ---------------> 0x04c9 Number of 512-bytes pages - 01 -----------------> 0x01 Bootable flag - 01 -----------------> 0x01 Image type (0x01 = Application) - -00000010800000fe: Ext Flash text partition - - 00000010 -----------> 0x10000000 Start Address (external flash) - 8000 ---------------> 0x0080 Number of 512-bytes pages - 00 -----------------> 0x00 Bootable flag - fe -----------------> 0xFE Image type (0xFE = Ext Flash text) - -00000110300200fc : OTA Image partition - - 00000110 -----------> 0x10010000 Start Address - 3002----------------> 0x0230 Number of 512-bytes pages - 00 -----------------> 0x00 Bootable flag - fc -----------------> 0xFC Image type (0xFC = OTA partition) - -00000510100000fd: NVM partition - - 00000510 -----------> 0x10050000 Start Address - 1000 ---------------> 0x0010 Number of 512-bytes pages - 00 -----------------> 0x00 Bootable flag - fd -----------------> 0xFD Image type (0xFD = NVM partition) -``` - -First, image directory 0 (SSBL partition) must be written: - -``` -DK6Programmer.exe -V5 -s -P 1000000 -w image_dir_0=0000000010000000 -``` - -Here is the interpretation of the fields: - -``` -00000000 -> start address 0x00000000 -1000 -> size = 0x0010 pages of 512-bytes (= 8kB) -00 -> not bootable (only used by the SSBL to support SSBL update) -00 -> SSBL Image Type -``` - -Second, image directory 1 (application partition) must be written: - -``` -DK6Programmer.exe -V5 -s -P 1000000 -w image_dir_1=00400000C9040101 -``` - -Here is the interpretation of the fields: - -``` -00400000 -> start address 0x00004000 -C904 -> 0x4C9 pages of 512-bytes (= 612.5kB) -01 -> bootable flag -01 -> image type for the application -``` - -Please note the user can write additional partitions by writing -`image_dir_2/3/4` with the wanted configuration. - -### Writing the application - -DK6Programmer can be used for flashing the application: - -``` -DK6Programmer.exe -V2 -s -P 1000000 -Y -p FLASH@0x4000="chip-k32w0x-light-example.bin" -``` +The internal flash needs to be prepared for the OTA process. First 16K of the +internal flash needs to be populated with SSBL related data while the last 8.5K +of flash space is holding flash configuration related data. The space between +these two zones will be filled by the application. More details regarding the +internal flash space can be found in the +[linker file](../../../../third_party/nxp/nxp_matter_support/examples/platform/k32w0/app/ldscripts/chip-k32w0x-linker.ld). -If debugging is needed, MCUXpresso can be used then for flashing the -application. Please make sure that the application is written at address 0x4000: +The steps for building the SSBL binary with appropriate configuration and +writing to the board the binary and other OTA related configurations are +described in the +[K32W0x1 OTA guide](../../../../docs/guides/nxp/nxp_k32w0_ota_guide.md). -![FLASH_LOCATION](../../../../platform/nxp/k32w/k32w0/doc/images/flash_location.JPG) +Note that the application needs to be built using the +`chip_enable_ota_requestor=true` option. This is enabled in the configuration by +default if no `chip_enable_ota_requestor` explicit setting is done. ### OTA Testing The OTA topology used for OTA testing is illustrated in the figure below. Topology is similar with the one used for Matter Test Events. -![OTA_TOPOLOGY](../../../../platform/nxp/k32w/k32w0/doc/images/ota_topology.JPG) +![OTA_TOPOLOGY](../../../platform/nxp/k32w0/doc/images/ota_topology.JPG) The concept for OTA is the next one: @@ -701,21 +683,22 @@ The address for storing the custom OTA entry can also be specified: address that does not overlap with anything else. Please see more in the -[OTA image tool guide](../../../../../scripts/tools/nxp/ota/README.md). +[OTA image tool guide](../../../../scripts/tools/nxp/ota/README.md). Here is an example that generates an OTA image with application update TLV: ``` -./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 42021 -vs "1.0" -da sha256 --app-input-file chip-k32w0x-light-example.bin chip-k32w0x-light-example.ota +./scripts/tools/nxp/ota/ota_image_tool.py create -v 0xDEAD -p 0xBEEF -vn 2 -vs "2.0" -da sha256 --app-input-file chip-k32w0x-light-example.bin chip-k32w0x-light-example.ota ``` A note regarding OTA image header version (`-vn` option). An application binary has its own software version, given by -`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION` (`42020` by default), which can be +`CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION` (`1` by default), which can be overwritten. For having a correct OTA process, the OTA header version should be -the same as the binary embedded software version. A user can set a custom -software version in the gn build args by setting `chip_software_version` to the -wanted version. +the same as the binary embedded software version. When building the update +image, the build arguments `nxp_software_version=2` and +`nxp_sofware_version_string=\"2.0\"` can be added to the gn gen command in order +to specify the upgraded version. Start the OTA Provider Application: @@ -745,7 +728,7 @@ Start the OTA process: user@computer1:~/connectedhomeip$ : ./out/chip-tool-app/chip-tool otasoftwareupdaterequestor announce-otaprovider 1 0 0 0 2 0 ``` -## Known issues ota +### Known issues OTA - SRP cache on the openthread border router needs to flushed each time a new commissioning process is attempted. For this, factory reset the device, then diff --git a/examples/lighting-app/nxp/k32w/k32w0/args.gni b/examples/lighting-app/nxp/k32w0/args.gni similarity index 96% rename from examples/lighting-app/nxp/k32w/k32w0/args.gni rename to examples/lighting-app/nxp/k32w0/args.gni index f5fd7a83cd9005..7126cf38ad5f3b 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/args.gni +++ b/examples/lighting-app/nxp/k32w0/args.gni @@ -20,6 +20,7 @@ k32w0_sdk_target = get_label_info(":sdk", "label_no_toolchain") chip_enable_ota_requestor = true chip_stack_lock_tracking = "fatal" chip_enable_ble = true +chip_generate_link_map_file = true is_debug = false diff --git a/examples/lighting-app/nxp/k32w0/build_overrides b/examples/lighting-app/nxp/k32w0/build_overrides new file mode 120000 index 00000000000000..ee19c065d619a2 --- /dev/null +++ b/examples/lighting-app/nxp/k32w0/build_overrides @@ -0,0 +1 @@ +../../../build_overrides/ \ No newline at end of file diff --git a/examples/lighting-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h b/examples/lighting-app/nxp/k32w0/include/CHIPProjectConfig.h similarity index 97% rename from examples/lighting-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h rename to examples/lighting-app/nxp/k32w0/include/CHIPProjectConfig.h index e32575e55ff5c4..62b2b0273f1da4 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/include/CHIPProjectConfig.h +++ b/examples/lighting-app/nxp/k32w0/include/CHIPProjectConfig.h @@ -86,7 +86,7 @@ 0xe4, 0x76, 0x1b, 0xfd, 0x05, \ } -// All remaining data will be pulled from provisioning region of flash. +// All remaining data will be pulled from the provisioning region of flash. #endif #else @@ -146,11 +146,11 @@ * {MAJOR_VERSION}.0d{MINOR_VERSION} */ #ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING -#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING "03-2022-te8" +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING NXP_CONFIG_DEVICE_SOFTWARE_VERSION_STRING #endif #ifndef CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION -#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION 42020 +#define CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION NXP_CONFIG_DEVICE_SOFTWARE_VERSION #endif #ifndef CHIP_DEVICE_CONFIG_DEVICE_VENDOR_NAME diff --git a/examples/lighting-app/nxp/k32w/k32w0/include/FreeRTOSConfig.h b/examples/lighting-app/nxp/k32w0/include/FreeRTOSConfig.h similarity index 100% rename from examples/lighting-app/nxp/k32w/k32w0/include/FreeRTOSConfig.h rename to examples/lighting-app/nxp/k32w0/include/FreeRTOSConfig.h diff --git a/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp b/examples/lighting-app/nxp/k32w0/main/AppTask.cpp similarity index 98% rename from examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp rename to examples/lighting-app/nxp/k32w0/main/AppTask.cpp index 22535a1c974c92..7db25b0a7c0451 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/main/AppTask.cpp +++ b/examples/lighting-app/nxp/k32w0/main/AppTask.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -44,9 +43,10 @@ #include #include #include -#include +#include #endif +#include "DefaultTestEventTriggerDelegate.h" #include "Keyboard.h" #include "LED.h" #include "LEDWidget.h" @@ -116,7 +116,7 @@ static BDXDownloader gDownloader; constexpr uint16_t requestedOtaBlockSize = 1024; #endif -#if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA && CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA && CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR CHIP_ERROR CustomFactoryDataRestoreMechanism(void) { K32W_LOG("This is a custom factory data restore mechanism."); @@ -151,7 +151,7 @@ static void CheckOtaEntry() if (ota_entries.ota_state == otaApplied) { K32W_LOG("OTA successfully applied"); -#if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA && CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA && CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR // If this point is reached, it means OTA_CommitCustomEntries was successfully called. // Delete the factory data backup to stop doing a restore when the factory data provider // is initialized. This ensures that both the factory data and app were updated, otherwise @@ -187,9 +187,8 @@ CHIP_ERROR AppTask::Init() CheckOtaEntry(); #endif - // Initialize device attestation config #if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA -#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR sFactoryDataProvider.RegisterRestoreMechanism(CustomFactoryDataRestoreMechanism); #endif ReturnErrorOnFailure(sFactoryDataProvider.Init()); diff --git a/examples/lighting-app/nxp/k32w/k32w0/main/LightingManager.cpp b/examples/lighting-app/nxp/k32w0/main/LightingManager.cpp similarity index 100% rename from examples/lighting-app/nxp/k32w/k32w0/main/LightingManager.cpp rename to examples/lighting-app/nxp/k32w0/main/LightingManager.cpp diff --git a/examples/lighting-app/nxp/k32w/k32w0/main/ZclCallbacks.cpp b/examples/lighting-app/nxp/k32w0/main/ZclCallbacks.cpp similarity index 100% rename from examples/lighting-app/nxp/k32w/k32w0/main/ZclCallbacks.cpp rename to examples/lighting-app/nxp/k32w0/main/ZclCallbacks.cpp diff --git a/examples/lighting-app/nxp/k32w/k32w0/main/include/AppEvent.h b/examples/lighting-app/nxp/k32w0/main/include/AppEvent.h similarity index 100% rename from examples/lighting-app/nxp/k32w/k32w0/main/include/AppEvent.h rename to examples/lighting-app/nxp/k32w0/main/include/AppEvent.h diff --git a/examples/lighting-app/nxp/k32w/k32w0/main/include/AppTask.h b/examples/lighting-app/nxp/k32w0/main/include/AppTask.h similarity index 95% rename from examples/lighting-app/nxp/k32w/k32w0/main/include/AppTask.h rename to examples/lighting-app/nxp/k32w0/main/include/AppTask.h index 0c455f431a8cf4..7dca1f700f6b89 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/main/include/AppTask.h +++ b/examples/lighting-app/nxp/k32w0/main/include/AppTask.h @@ -27,7 +27,7 @@ #include "CHIPProjectConfig.h" #if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA -#include +#include #if CHIP_DEVICE_CONFIG_USE_CUSTOM_PROVIDER #include "CustomFactoryDataProvider.h" #endif @@ -50,6 +50,9 @@ class AppTask { public: +#if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA + using FactoryDataProvider = chip::DeviceLayer::FactoryDataProviderImpl; +#endif CHIP_ERROR StartAppTask(); static void AppTaskMain(void * pvParameter); diff --git a/examples/lighting-app/nxp/k32w/k32w0/main/include/LightingManager.h b/examples/lighting-app/nxp/k32w0/main/include/LightingManager.h similarity index 100% rename from examples/lighting-app/nxp/k32w/k32w0/main/include/LightingManager.h rename to examples/lighting-app/nxp/k32w0/main/include/LightingManager.h diff --git a/examples/lighting-app/nxp/k32w/k32w0/main/include/app_config.h b/examples/lighting-app/nxp/k32w0/main/include/app_config.h similarity index 100% rename from examples/lighting-app/nxp/k32w/k32w0/main/include/app_config.h rename to examples/lighting-app/nxp/k32w0/main/include/app_config.h diff --git a/examples/lighting-app/nxp/k32w/k32w0/main/main.cpp b/examples/lighting-app/nxp/k32w0/main/main.cpp similarity index 97% rename from examples/lighting-app/nxp/k32w/k32w0/main/main.cpp rename to examples/lighting-app/nxp/k32w0/main/main.cpp index a8963a17c09096..6d95f10fe1168b 100644 --- a/examples/lighting-app/nxp/k32w/k32w0/main/main.cpp +++ b/examples/lighting-app/nxp/k32w0/main/main.cpp @@ -139,7 +139,7 @@ extern "C" void main_task(void const * argument) */ sched_enable(); - err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_MinimalEndDevice); + err = ConnectivityMgr().SetThreadDeviceType(CONNECTIVITY_MANAGER_THREAD_DEVICE_TYPE); if (err != CHIP_NO_ERROR) { goto exit; diff --git a/examples/lighting-app/nxp/k32w0/third_party/connectedhomeip b/examples/lighting-app/nxp/k32w0/third_party/connectedhomeip new file mode 120000 index 00000000000000..3efed95be5dbe9 --- /dev/null +++ b/examples/lighting-app/nxp/k32w0/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../../ \ No newline at end of file diff --git a/examples/platform/nxp/k32w/k32w0/BUILD.gn b/examples/platform/nxp/k32w/k32w0/BUILD.gn deleted file mode 100644 index eb0c79742f3b99..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/BUILD.gn +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2020 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("//build_overrides/chip.gni") -import("//build_overrides/nxp_sdk.gni") - -import("${nxp_sdk_build_root}/nxp_sdk.gni") - -import("${nxp_sdk_build_root}/${nxp_sdk_name}/${nxp_sdk_name}.gni") - -config("chip_examples_project_config") { - include_dirs = [ - "app/project_include", - "${chip_root}", - ] -} - -source_set("openthread_core_config_k32w0_chip_examples") { - sources = [ "app/project_include/OpenThreadConfig.h" ] - - public_deps = [ "${chip_root}/third_party/openthread/platforms/nxp/k32w/k32w0:openthread_core_config_k32w0" ] - - public_configs = [ ":chip_examples_project_config" ] -} diff --git a/examples/platform/nxp/k32w/k32w0/app/BUILD.gn b/examples/platform/nxp/k32w/k32w0/app/BUILD.gn deleted file mode 100644 index 8651bd56be4ecd..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/app/BUILD.gn +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (c) 2020 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("//build_overrides/chip.gni") - -config("chip_examples_project_config") { - include_dirs = [ "app/project_include" ] -} - -source_set("openthread_core_config_k32w0_chip_examples") { - sources = [ "app/project_include/OpenThreadConfig.h" ] - - public_deps = [ "${chip_root}/third_party/openthread/platforms/nxp/k32w/k32w0:openthread_core_config_k32w0" ] - - public_configs = [ ":chip_examples_project_config" ] -} diff --git a/examples/platform/nxp/k32w/k32w0/app/args.gni b/examples/platform/nxp/k32w/k32w0/app/args.gni deleted file mode 100644 index 44a96b88a65b1b..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/app/args.gni +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (c) 2020 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("//build_overrides/chip.gni") - -import("${chip_root}/src/platform/nxp/k32w/k32w0/args.gni") - -openthread_project_core_config_file = "OpenThreadConfig.h" - -chip_ble_project_config_include = "" -chip_device_project_config_include = "" -chip_project_config_include = "" -chip_inet_project_config_include = "" -chip_system_project_config_include = "" - -chip_system_config_provide_statistics = false -chip_with_nlfaultinjection = true diff --git a/examples/platform/nxp/k32w/k32w0/app/ldscripts/chip-k32w0x-linker.ld b/examples/platform/nxp/k32w/k32w0/app/ldscripts/chip-k32w0x-linker.ld deleted file mode 100644 index c51182b104ec53..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/app/ldscripts/chip-k32w0x-linker.ld +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (c) 2019, The OpenThread Authors. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file - * GCC linker script for K32W061/K32W041. - */ - -/******************* Map of K32W0 internal flash *********************************** - - 0x000A_0000 - - - - +---------------+ - - - - - - - - - | | - 8.5K | Flash config | - | RESERVED | 0x0009_DE00 - - - - +---------------+ - - - - - - - - - | | - 2K | Factory data | - | | 0x0009_D600 - - - - +---------------+ - - - - - - - - - | | - 1K | App metadata | - | | 0x0009_D200 - - - - +---------------+ - - - - - - - - - | | - 612.5K | Application | - | | 0x0000_4000 - - - - +---------------+ - - - - - - - - - | | - 8K | SSBL update | - | | 0x0000_2000 - - - - +---------------+ - - - - - - - - - | | - 8K | SSBL | - | | 0x0000_0000 - - - - +---------------+ - - - - - - - - - 0x0000_0000 - -* - If OTA is disabled, SSBL and SSBL updated region are not present. - - The only address range that changes is the application, which will span from - 0x0000_0000 to 0x0009_D200, having 628.5K max size. - *****************************************************************************/ - -/******************* Map of DK6 external flash *********************************** - - 0x0010_0000 - - - - +---------------+ - - - - - - - - - | | - 252K | PDM area | - | | 0x000C_1000 - - - - +---------------+ - - - - - - - - - | | - 4K | OTA entry | - | | 0x000C_0000 - - - - +---------------+ - - - - - - - - - | | - 768K | OTA area | - | | - - - - +---------------+ - - - - - - - - - 0x0000_0000 - - *****************************************************************************/ - -OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") - -/* - * stack size for the boot rom during warm boot and application - * 256 is sufficient (pwrm_test) but keep it large to 1024 - */ -BOOT_RESUME_STACK_SIZE = 1024; - -STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x01000; - -MEM_RAM0_BASE = 0x4000400; -MEM_RAM0_SIZE = 0x0015c00; - -MEM_RAM1_BASE = 0x4020000; -MEM_RAM1_SIZE = 0x10000; - -/* internal flash size: 640K */ -m_int_flash_size = 0xA0000; -m_int_sector_size = 512; - -/* first 8K: SSBL, next 8K: SSBL update region */ -m_app_start = DEFINED(__app_load_address__) ? __app_load_address__ : 0x0; - -/* flash_config: 8.5K */ -m_flash_config_size = 0x2200; - -/* sizeof(BOOT_BLOCK_T) + sizeof(IMAGE_CERT_T) + SIGNATURE_LEN + alignment = 1024 bytes */ -m_app_meta_data = 0x400; - -/* manufacturing data: 2K */ -m_factory_data_size = 0x800; - -/* 16K: SSBL + SSBL update region */ -m_ssbl_size = 0x4000; - -/* default app size, without OTA */ -m_app_default_size = m_int_flash_size - m_flash_config_size - m_app_meta_data - m_factory_data_size; - -m_app_size = DEFINED(__app_stated_size__) ? __app_stated_size__ : m_app_default_size; - -MEMORY -{ - Flash640 (rx) : ORIGIN = m_app_start, LENGTH = m_app_size - - SCRATCH_RAM(rwx) : ORIGIN = 0x4000000, LENGTH = 0x400 /* 1K bytes (alias SCRATCH_RAM) */ - RAM0 (rwx) : ORIGIN = 0x4000400, LENGTH = 0x0015BE0 /* [87K - 32] bytes (alias RAM) */ - reserved (rwx) : ORIGIN = 0x4015FE0, LENGTH = 0x20 /* 32 bytes (reserved for ROM code) */ - RAM1 (rwx) : ORIGIN = 0x4020000, LENGTH = 0x10000 /* 64K bytes (alias RAM2) */ -} - -/* Define a symbol for the top of each memory region */ -__top_RAM1 = MEM_RAM1_BASE + MEM_RAM1_SIZE; /* 64K bytes */ - -/* The second RAM bank is dedicated entirely to heap + stack. */ -HEAP_SIZE = MEM_RAM1_SIZE - STACK_SIZE; -ASSERT(((HEAP_SIZE + STACK_SIZE) == MEM_RAM1_SIZE), "Heap size + stack size should total RAM1 size."); - -/* set external flash properties - external flash is present on the DK6 board */ -m_ext_flash_size = 0x00100000; -m_ext_flash_base = 0x00000000; -m_ext_flash_sector_size = 4096; - -NVMSectorCountLink = 63; - -NV_STORAGE_SIZE = NVMSectorCountLink * m_ext_flash_sector_size; -NV_STORAGE_MAX_SECTORS = NVMSectorCountLink; -NV_STORAGE_SECTOR_SIZE = m_ext_flash_sector_size; -NV_STORAGE_START_ADDRESS = m_ext_flash_size - 1; -NV_STORAGE_END_ADDRESS = NV_STORAGE_START_ADDRESS - NV_STORAGE_SIZE + 1; - -INT_STORAGE_START = m_int_flash_size - 1; -INT_STORAGE_SIZE = m_int_flash_size; -INT_STORAGE_END = 0x00000000; -INT_STORAGE_SECTOR_SIZE = m_int_sector_size; - -FACTORY_DATA_START_ADDRESS = m_int_flash_size - m_flash_config_size - m_factory_data_size; -FACTORY_DATA_END_ADDRESS = FACTORY_DATA_START_ADDRESS + m_factory_data_size - 1; - -__ram_vector_table__ = 1; -vector_table_size = 0x120; -M_VECTOR_RAM_SIZE = DEFINED(__ram_vector_table__) ? vector_table_size : 0x0; - -__base_RAM0 = 0x4000400; - -ENTRY(ResetISR) - -SECTIONS -{ - /* MAIN TEXT SECTION */ - .header : ALIGN(4) - { - _flash_start = ABSOLUTE(.); - _flash_beg = ABSOLUTE(.); - - FILL(0xff) - __vectors_start__ = ABSOLUTE(.) ; - __VECTOR_TABLE = .; - __Vectors = .; - KEEP(*(.isr_vector)) - /* Global Section Table */ - . = ALIGN(4) ; - __section_table_start = .; - __data_section_table = .; - LONG(LOADADDR(.data)); - LONG( ADDR(.data)); - LONG( SIZEOF(.data)); - __data_section_table_end = .; - __bss_section_table = .; - LONG( ADDR(.bss)); - LONG( SIZEOF(.bss)); - __bss_section_table_end = .; - __section_table_end = . ; - /* End of Global Section Table */ - - FILL(0xff) - . = ALIGN (0x10); - } >Flash640 - - .ro_nonce : ALIGN(0x10) - { - _FlsNonceStart = ABSOLUTE(.); - *(.ro_nonce) /* nonce value is 16 bytes.*/ - FILL(0xff) - . = ALIGN (0x10); - } > Flash640 - - .ro_ota_header : ALIGN(0x10) - { - _enc_start = ABSOLUTE(.); - _enc_offset = (_enc_start & 0x0000000F); - _FlsOtaHeader = ABSOLUTE(.); - *(.ro_ota_header) /* Ota Header 69 bytes*/ - FILL(0xff) - . = ALIGN (0x10); - } > Flash640 - - .ro_se_lnkKey (ALIGN((. - _enc_offset), 16) + _enc_offset): - { - _FlsLinkKey = ABSOLUTE(.); - *(.ro_se_lnkKey) /* Link Key 16 bytes*/ - FILL(0xff) - . = ALIGN (0x10); - } > Flash640 - - .filler : - { - BYTE(0xff); - FILL(0xff); - . = ALIGN(0x40); - } > Flash640 - - .text : ALIGN(0x40) - { - FILL(0xff) - - *(.after_vectors*) - *(.text*) - - KEEP(*(.init)) - KEEP(*(.fini)) - - /* .ctors */ - *crtbegin.o(.ctors) - *crtbegin?.o(.ctors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) - *(SORT(.ctors.*)) - *(.ctors) - - /* .dtors */ - *crtbegin.o(.dtors) - *crtbegin?.o(.dtors) - *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) - *(SORT(.dtors.*)) - *(.dtors) - - *(.rodata .rodata.* .constdata .constdata.*) - - . = ALIGN(4); - } > Flash640 - /* - * for exception handling/unwind - some Newlib functions (in common - * with C++ and STDC++) use this. - */ - .ARM.extab : ALIGN(4) - { - FILL(0xff) - *(.ARM.extab* .gnu.linkonce.armextab.*) - } > Flash640 - __exidx_start = .; - - .ARM.exidx : ALIGN(4) - { - FILL(0xff) - *(.ARM.exidx* .gnu.linkonce.armexidx.*) - } > Flash640 - __exidx_end = .; - - _etext = .; - - .heap (COPY): - { - __HeapBase = .; - _heap = .; - KEEP(*(.heap*)) - PROVIDE(end = .); - . = ALIGN(4); - __end__ = .; - _end_heap = .; - __HeapLimit = .; - } > RAM1 - - .interrupts_ram : ALIGN(0x200) - { - . = ALIGN(4); - __VECTOR_RAM__ = .; - __interrupts_ram_start__ = .; /* Create a global symbol at data start */ - *(.m_interrupts_ram) /* This is a user defined section */ - . += M_VECTOR_RAM_SIZE; - . = ALIGN(4); - __interrupts_ram_end__ = .; /* Define a global symbol at data end */ - } > RAM0 - .scratch_area (NOLOAD): ALIGN(4) - { - __scratch_area_start__ = .; - . = ALIGN(4) ; - . += 0x400; - __scratch_area_top__ = .; - } > SCRATCH_RAM - - /* MAIN DATA SECTION */ - .uninit_RESERVED : ALIGN(4) - { - KEEP(*(.bss.$RESERVED*)) - . = ALIGN(4) ; - _end_uninit_RESERVED = .; - } > RAM0 - - /* Main DATA section (RAM0) */ - .data : ALIGN(4) - { - FILL(0xff) - _data = . ; - *(vtable) - *(.ramfunc*) - *(.data*) - - . = ALIGN(4); - /* preinit data */ - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP(*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - - . = ALIGN(4); - /* init data */ - __init_array_start = . ; - KEEP(*(SORT(.init_array.*))) - KEEP(*(.init_array)) - __init_array_end = . ; - - . = ALIGN(4); - /* finit data */ - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP(*(SORT(.fini_array.*))) - KEEP(*(.fini_array)) - PROVIDE_HIDDEN (__fini_array_end = .); - - KEEP(*(.jcr*)) - - . = ALIGN(4) ; - _edata = . ; - } > RAM0 AT>Flash640 - - __VECTOR_RAM = __VECTOR_RAM__; - __RAM_VECTOR_TABLE_SIZE_BYTES = DEFINED(__ram_vector_table__) ? (__interrupts_ram_end__ - __interrupts_ram_start__) : 0x0; - - /* MAIN BSS SECTION */ - .bss (NOLOAD) : ALIGN(4) - { - _bss = .; - *(.bss*) - *(COMMON) - *(g_u32NwkFrameCounter) - . = ALIGN(4) ; - _ebss = .; - - PROVIDE(end = .); - } > RAM0 - - /* BSS section for MAC buffers */ - .bss_MAC (NOLOAD) : ALIGN(4) - { - /* MAC buffer section: must be within 128kB block. __mac_buffer_base is - defined further down to be on 128kB alignment */ - __mac_buffer_start = .; - *(.mac_buffer) - - . = ALIGN (. != 0 ? 4 : 1) ; /* avoid empty segment */ - } > RAM0 - - /* BSS section for unretained contents */ - .bss_discard (NOLOAD) : ALIGN(4) - { - *(.discard.bss.pdm) - - . = ALIGN (. != 0 ? 4 : 1) ; /* avoid empty segment */ - } > RAM0 - - /* DEFAULT NOINIT SECTION */ - .noinit (NOLOAD): ALIGN(4) - { - _noinit = .; - *(.noinit*) - . = ALIGN(4) ; - _end_noinit = .; - } > RAM0 - - /* end of firmware RAM to be retained in power down mode */ - _end_fw_retention = .; - - /* non retained RAM section */ - /* stack for rom boot during warm resume */ - .boot_resume_stack (NOLOAD): ALIGN(4) - { - _boot_resume_stack = .; - *(.boot_resume_stack*) - . += BOOT_RESUME_STACK_SIZE; - . = ALIGN(4) ; - _end_boot_resume_stack = .; - } > RAM0 - - __nv_storage_end_address = NV_STORAGE_END_ADDRESS; - __nv_storage_start_address = NV_STORAGE_START_ADDRESS; - - PROVIDE(_vStackTop = __top_RAM1); - PROVIDE(__mac_buffer_base = (__mac_buffer_start & 0xfffe0000)); - PROVIDE(BOOT_GetStartPowerMode = 0x03000e9d); - PROVIDE(ROM_GetFlash = 0x03000e0d); - PROVIDE(pmc_reset_get_cause = 0x030046e9); - PROVIDE(psector_ReadIeee802_15_4_MacId1 = 0x030053b1); - PROVIDE(Chip_LOWPOWER_ChipSoftwareReset = 0x03003fa1); - PROVIDE(_pvHeapStart = _heap); - PROVIDE(_pvHeapLimit = _pvHeapStart + (HEAP_SIZE)); - PROVIDE(_scratch_buf_start = __scratch_area_start__); - PROVIDE(_scratch_buf_end = __scratch_area_top__); - - __StackLimit = _vStackTop - STACK_SIZE; - ASSERT(__StackLimit >= _end_heap, "Stack and heap spaces are overlapping!") - - __MATTER_FACTORY_DATA_START = FACTORY_DATA_START_ADDRESS; - __MATTER_FACTORY_DATA_SIZE = m_factory_data_size; - - /* The .ro_version section inside SSBL is set after the .m_interrupts sections, - * which is assumed to never change, so the offset remains the same across different - * SSBL versions. This symbol is used in Matter Application to retrieve the SSBL version. */ - __MATTER_SSBL_VERSION_START = 0x00000120; - - ASSERT(((m_app_start + m_app_size + m_app_meta_data + m_factory_data_size + m_flash_config_size) <= m_int_flash_size), - "Internal flash capacity exceeded") - -} diff --git a/examples/platform/nxp/k32w/k32w0/app/project_include/OpenThreadConfig.h b/examples/platform/nxp/k32w/k32w0/app/project_include/OpenThreadConfig.h deleted file mode 100644 index d76a51a6fbb55b..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/app/project_include/OpenThreadConfig.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * - * Copyright (c) 2020 Google LLC. - * All rights reserved. - * - * 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. - */ - -/** - * @file - * Overrides to default OpenThread configuration. - * - */ - -#include "openthread-core-k32w061-config.h" - -#pragma once - -// Disable the Nxp-supplied OpenThread logging facilities -// and use the facilities provided by the Device Layer -// (see src/platform/K32W/Logging.cpp). -#undef OPENTHREAD_CONFIG_LOG_OUTPUT -#define OPENTHREAD_CONFIG_LOG_OUTPUT OPENTHREAD_CONFIG_LOG_OUTPUT_APP - -// When operating in a less than ideal RF environment, having a more forgiving configuration -// of OpenThread makes thread a great deal more reliable. -#undef OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY -#define OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY 120 // default is 28800 - -#undef OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_DIRECT -#define OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_DIRECT 15 // default is 3 - -#undef OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_INDIRECT -#define OPENTHREAD_CONFIG_MAC_DEFAULT_MAX_FRAME_RETRIES_INDIRECT 1 // default is 0 - -#undef OPENTHREAD_CONFIG_MAC_MAX_TX_ATTEMPTS_INDIRECT_POLLS -#define OPENTHREAD_CONFIG_MAC_MAX_TX_ATTEMPTS_INDIRECT_POLLS 16 // default is 4 - -// Enable periodic parent search to speed up finding a better parent. -#undef OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE -#define OPENTHREAD_CONFIG_PARENT_SEARCH_ENABLE 1 // default is 0 - -#undef OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD -#define OPENTHREAD_CONFIG_PARENT_SEARCH_RSS_THRESHOLD -45 // default is -65 - -#undef OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH -#define OPENTHREAD_CONFIG_MLE_INFORM_PREVIOUS_PARENT_ON_REATTACH 1 // default is 0 - -// Use smaller maximum interval to speed up reattaching. -#undef OPENTHREAD_CONFIG_MLE_ATTACH_BACKOFF_MAXIMUM_INTERVAL -#define OPENTHREAD_CONFIG_MLE_ATTACH_BACKOFF_MAXIMUM_INTERVAL (60 * 10 * 1000) // default 1200000 ms - -// disable unused features -#undef OPENTHREAD_CONFIG_COAP_API_ENABLE -#define OPENTHREAD_CONFIG_COAP_API_ENABLE 0 - -#undef OPENTHREAD_CONFIG_JOINER_ENABLE -#define OPENTHREAD_CONFIG_JOINER_ENABLE 0 - -#undef OPENTHREAD_CONFIG_COMMISSIONER_ENABLE -#define OPENTHREAD_CONFIG_COMMISSIONER_ENABLE 0 - -#undef OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE -#define OPENTHREAD_CONFIG_UDP_FORWARD_ENABLE 0 - -#undef OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE -#define OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 0 - -#undef OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE -#define OPENTHREAD_CONFIG_DHCP6_CLIENT_ENABLE 0 - -#undef OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE -#define OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE 0 - -#undef OPENTHREAD_CONFIG_TCP_ENABLE -#define OPENTHREAD_CONFIG_TCP_ENABLE 0 - -#undef OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE -#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE 0 - -#undef OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE -#define OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE 0 - -#undef OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS -#define OPENTHREAD_CONFIG_NUM_MESSAGE_BUFFERS 44 - -#undef OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE -#define OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE 0 - -#undef OPENTHREAD_CONFIG_SRP_SERVER_ENABLE -#define OPENTHREAD_CONFIG_SRP_SERVER_ENABLE 0 - -#undef OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE -#define OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 0 - -#define UART_USE_SERIAL_MGR 1 -#define UART_USE_SERIAL_MGR_LOG 1 - -// #define OPENTHREAD_CONFIG_LOG_LEVEL OT_LOG_LEVEL_DEBG - -// Use the NXP-supplied default platform configuration for remainder -// of OpenThread config options. -// -// NB: This file gets included during the build of OpenThread. Hence -// it cannot use "openthread" in the path to the included file. -// diff --git a/examples/platform/nxp/k32w/k32w0/app/support/BUILD.gn b/examples/platform/nxp/k32w/k32w0/app/support/BUILD.gn deleted file mode 100644 index 7b10c468a02fe6..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/app/support/BUILD.gn +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright (c) 2020 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("//build_overrides/chip.gni") -import("//build_overrides/nxp_sdk.gni") - -config("support_config") { - include_dirs = [ "../../../../.." ] - - # Link options that provides replace dynamic memory operations in standard - # library with the FreeRTOS malloc in platform code. - ldflags = [ - # memory allocation -- these must be re-entrant and do locking - "-Wl,--wrap=malloc", - "-Wl,--wrap=free", - "-Wl,--wrap=realloc", - "-Wl,--wrap=calloc", - "-Wl,--wrap=MemoryAlloc", - - # Wrap these in case internal newlib call them (e.g. strdup will) - # directly call _malloc_r) - "-Wl,--wrap=_malloc_r", - "-Wl,--wrap=_realloc_r", - "-Wl,--wrap=_free_r", - "-Wl,--wrap=_calloc_r", - ] -} - -source_set("freertos_mbedtls_utils") { - sources = [ - "FreeRtosHooks.c", - "FreeRtosHooks.h", - "Memconfig.cpp", - ] - - deps = [ "${chip_root}/src/lib/support" ] - - cflags = [ "-Wconversion" ] - - public_configs = [ ":support_config" ] -} diff --git a/examples/platform/nxp/k32w/k32w0/app/support/FreeRtosHooks.c b/examples/platform/nxp/k32w/k32w0/app/support/FreeRtosHooks.c deleted file mode 100644 index 59cae3f6d14cf9..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/app/support/FreeRtosHooks.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * - * Copyright (c) 2020 Google LLC. - * All rights reserved. - * - * 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. - * - */ - -#include "FreeRtosHooks.h" - -#include "FreeRTOS.h" -#include "semphr.h" - -#include - -#include -#include - -#include "PDM.h" -#include "PWR_Interface.h" -#include "TimersManager.h" -#include "board.h" -#include "pdm_ram_storage_glue.h" - -/* Bluetooth Low Energy */ -#include "ble_config.h" -#include "l2ca_cb_interface.h" - -#include "controller_interface.h" - -#if defined gLoggingActive_d && (gLoggingActive_d > 0) -#include "dbg_logging.h" -#ifndef DBG_APP -#define DBG_APP 0 -#endif -#define APP_DBG_LOG(fmt, ...) \ - if (DBG_APP) \ - do \ - { \ - DbgLogAdd(__FUNCTION__, fmt, VA_NUM_ARGS(__VA_ARGS__), ##__VA_ARGS__); \ - } while (0); -#else -#define APP_DBG_LOG(...) -#endif - -#if (configUSE_TICKLESS_IDLE != 0) -#define DBG_PostStepTickAssess 0 -#if DBG_PostStepTickAssess && !gTimestampUseWtimer_c -#error "gTimestampUseWtimer_c required for DBG_PostStepTickAssess" -#endif -#if defined(gPWR_FreqScalingWFI) && (gPWR_FreqScalingWFI != 0) -/* this MACRO is required when gPWR_FreqScalingWFI is not equal to zero (system clock frequency - reduced in WFI) */ -#define App_SuppressTickInStopMode 1 -#else -#define App_SuppressTickInStopMode 0 -#endif -#if gPWR_CpuClk_48MHz -/* for systick accuracy, this is recommended to enable FRO calibration */ -#define gApp_SystemClockCalibration 1 -#endif -#endif - -#define PDM_MAX_WRITES_INFINITE 0xFF - -static inline void mutex_init(mbedtls_threading_mutex_t * p_mutex) -{ - assert(p_mutex != NULL); - *p_mutex = xSemaphoreCreateMutex(); - assert(*p_mutex != NULL); -} - -static inline void mutex_free(mbedtls_threading_mutex_t * p_mutex) -{ - assert(p_mutex != NULL); - assert(*p_mutex != NULL); - vSemaphoreDelete(*p_mutex); -} - -static inline int mutex_lock(mbedtls_threading_mutex_t * p_mutex) -{ - assert(p_mutex != NULL); - assert(*p_mutex != NULL); - return xSemaphoreTake(*p_mutex, portMAX_DELAY) != pdTRUE; -} - -static inline int mutex_unlock(mbedtls_threading_mutex_t * p_mutex) -{ - assert(p_mutex != NULL); - assert(*p_mutex != NULL); - return xSemaphoreGive(*p_mutex) != pdTRUE; -} - -void freertos_mbedtls_mutex_init(void) -{ - mbedtls_threading_set_alt(mutex_init, mutex_free, mutex_lock, mutex_unlock); -} - -void freertos_mbedtls_mutex_free(void) -{ - mbedtls_threading_free_alt(); -} - -#if (configUSE_TICKLESS_IDLE != 0) - -/* - * Setup the systick timer to generate the tick interrupts at the required - * frequency. - */ -void vPortSetupTimerInterrupt(void) -{ - /* Stop and clear the SysTick. */ - SysTick->CTRL = 0UL; - SysTick->VAL = 0UL; - -#if DBG_PostStepTickAssess - tickless_SystickCheckDriftInit(); -#endif - - /* configure module for tickless mode */ - tickless_init(); - -#if gApp_SystemClockCalibration - /* calibration on the internal FRO48MHz clock - this clock is inaccurate (2%), - * so it needs calibration if we want the systick to be accurate to less - * than 500pp. */ - tickless_StartFroCalibration(); -#endif - - /* Configure SysTick to interrupt at the requested rate. */ - SysTick_Config(CLOCK_GetFreq(kCLOCK_CoreSysClk) / configTICK_RATE_HZ); -} - -void vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime) -{ - tmrlp_tickless_systick_t lp_ctx; - APP_DBG_LOG("xExpectedIdleTime = %d ticks %d ms", xExpectedIdleTime, xExpectedIdleTime * portTICK_PERIOD_MS); - OSA_InterruptDisable(); - - /* Do not go to sleep, lowpower or WFI if there is a pending task to schedule - * Scheduler is suspended when calling vPortSuppressTicksAndSleep, - * as interrupt are disabled if one is pending, eTaskConfirmSleepModeStatus - * will prevent sleep. - */ - if (eTaskConfirmSleepModeStatus() == eAbortSleep) - { - APP_DBG_LOG("task to schedule"); - /* Do nothing */ - } -#if gApp_SystemClockCalibration - /* Prevent lowpower / tickless mode if cal ongoing - get estimated core freq */ - else if (tickless_EstimateCoreClockFreq()) - { - /* can eventually enter sleep or re evaluate on next idle loop, the calibration shall take 4 ms average */ - // PWR_EnterSleep(); - } -#endif - - /* Do not go to power down if: - * - the RTOS is expecting a wake-up too close to the current date - * To worth a power down the xExpectedIdleTime should be - * > to 2 rtos tick (which includes residual_count worst margin + carry after wake-up worst margin) - * + enter/exist power down duration converted in RTOS tick - * - power down is not allowed - */ - else if ((xExpectedIdleTime > - (2 + ((PWR_SYSTEM_EXIT_LOW_POWER_DURATION_MS + PWR_SYSTEM_ENTER_LOW_POWER_DURATION_MS) / portTICK_PERIOD_MS) + 1))) - { - int result = PWR_CheckIfDeviceCanGoToSleepExt(); - if (result >= kPmPowerDown0) - { - PWR_WakeupReason_t wakeupReason; - lp_ctx.exitTicklessDuration32kTick = MILLISECONDS_TO_TICKS32K(PWR_SYSTEM_EXIT_LOW_POWER_DURATION_MS); - /* Tickless pre processing */ - tickless_PreProcessing(&lp_ctx, xExpectedIdleTime); - - /* Enter power down */ - wakeupReason = PWR_EnterPowerDown(); - - APP_DBG_LOG("wakeReason=%x", (uint16_t) wakeupReason.AllBits); - (void) wakeupReason; - - /* Tickless post processing */ - tickless_PostProcessing(&lp_ctx); - -#if DBG_PostStepTickAssess - if (wakeupReason.Bits.FromTMR == 1) - configASSERT(lp_ctx.idle_tick_jump == xExpectedIdleTime); - if (wakeupReason.Bits.DidPowerDown == 1) - configASSERT((wakeupReason.AllBits & ~0x8000U) != 0); -#endif - } - else if ((result == kPmSleep) || (result < 0)) - { -#if App_SuppressTickInStopMode - lp_ctx.exitTicklessDuration32kTick = 0; - /* Tickless pre processing */ - tickless_PreProcessing(&lp_ctx, xExpectedIdleTime); -#endif - - PWR_EnterSleep(); - -#if App_SuppressTickInStopMode - /* Tickless post processing */ - tickless_PostProcessing(&lp_ctx); -#endif - } - } - else - { -#if App_SuppressTickInStopMode - lp_ctx.exitTicklessDuration32kTick = 0; - /* Tickless pre processing */ - tickless_PreProcessing(&lp_ctx, xExpectedIdleTime); -#endif - - PWR_EnterSleep(); - -#if App_SuppressTickInStopMode - /* Tickless post processing */ - tickless_PostProcessing(&lp_ctx); -#endif - } - -#if DBG_PostStepTickAssess - tickless_SystickCheckDrift(); -#endif - - OSA_InterruptEnable(); -} -#endif /* (configUSE_TICKLESS_IDLE != 0) */ - -static void BOARD_ActionOnIdle(void) -{ -#if ((defined gTcxo32k_ModeEn_c) && (gTcxo32k_ModeEn_c != 0)) - BOARD_tcxo32k_compensation_run(2, 0); -#endif -#if ((defined gTcxo32M_ModeEn_c) && (gTcxo32M_ModeEn_c != 0)) - BOARD_tcxo32M_compensation_run(2, 10); /* 2 degrees - wait for 10us */ -#endif -} - -extern void OTAIdleActivities(void); -extern bool AppHaveBLEConnections(void); - -void vApplicationIdleHook(void) -{ -#if PDM_SAVE_IDLE - /* While in BLE connection during commissioning, PDM saves should be paused */ - if (!AppHaveBLEConnections()) - { - FS_vIdleTask(PDM_MAX_WRITES_INFINITE); - } -#endif - - OTAIdleActivities(); - -#if gAdcUsed_d - BOARD_ADCMeasure(); -#endif - - BOARD_ActionOnIdle(); -} diff --git a/examples/platform/nxp/k32w/k32w0/app/support/FreeRtosHooks.h b/examples/platform/nxp/k32w/k32w0/app/support/FreeRtosHooks.h deleted file mode 100644 index a27f72d498f81d..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/app/support/FreeRtosHooks.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * Copyright (c) 2020 Nest Labs, Inc. - * All rights reserved. - * - * 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. - */ - -#pragma once - -typedef void * mbedtls_threading_mutex_t; - -extern void mbedtls_threading_set_alt(void (*mutex_init)(mbedtls_threading_mutex_t *), - void (*mutex_free)(mbedtls_threading_mutex_t *), - int (*mutex_lock)(mbedtls_threading_mutex_t *), - int (*mutex_unlock)(mbedtls_threading_mutex_t *)); - -extern void mbedtls_threading_free_alt(void); - -#ifdef __cplusplus -extern "C" { -#endif - -/**@brief Function for initializing alternative MbedTLS mutexes to enable the usage of the FreeRTOS implementation. */ -void freertos_mbedtls_mutex_init(void); - -/**@brief Function for releasing MbedTLS alternative mutexes. */ -void freertos_mbedtls_mutex_free(void); - -#ifdef __cplusplus -} -#endif diff --git a/examples/platform/nxp/k32w/k32w0/app/support/Memconfig.cpp b/examples/platform/nxp/k32w/k32w0/app/support/Memconfig.cpp deleted file mode 100644 index e5acf5ea3ceecb..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/app/support/Memconfig.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * - * Copyright (c) 2020-2021 Project CHIP Authors - * All rights reserved. - * - * 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. - */ - -/** - * @file - * This file contains platform specific implementations for stdlib malloc/calloc/realloc/free - * functions, so that CHIPPlatformMemory* works as intended with the platform's heap. - */ - -#include "FreeRTOS.h" -#include "task.h" -#include -#include -#include - -#ifndef NDEBUG -#include -#include -#endif - -#include - -#if CHIP_CONFIG_MEMORY_DEBUG_DMALLOC -#include -#include -#endif // CHIP_CONFIG_MEMORY_DEBUG_DMALLOC - -/* Assumes 8bit bytes! */ -#define heapBITS_PER_BYTE ((size_t) 8) - -/* Define the linked list structure. This is used to link free blocks in order -of their memory address. */ -typedef struct A_BLOCK_LINK -{ - struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */ - size_t xBlockSize; /*<< The size of the free block. */ -} BlockLink_t; - -/* The size of the structure placed at the beginning of each allocated memory -block must by correctly byte aligned. */ -static const size_t xHeapStructSize = - (sizeof(BlockLink_t) + ((size_t) (portBYTE_ALIGNMENT - 1))) & ~((size_t) portBYTE_ALIGNMENT_MASK); - -/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize -member of an BlockLink_t structure is set then the block belongs to the -application. When the bit is free the block is still part of the free heap -space. */ -static size_t xBlockAllocatedBit = ((size_t) 1) << ((sizeof(size_t) * heapBITS_PER_BYTE) - 1); - -extern "C" { - -/* xPortMallocUsableSize relies on heap4 implementation. -It returns the size of an allocated block and it is -called by __wrap_realloc. -Thus it is validated in __wrap_realloc function that the allocated size -of the old_ptr is smaller than the allocated size of new_ptr */ -size_t xPortMallocUsableSize(void * pv) -{ - uint8_t * puc = (uint8_t *) pv; - BlockLink_t * pxLink; - void * voidp; - size_t sz = 0; - - if (pv != NULL) - { - vTaskSuspendAll(); - { - /* The memory being checked will have an BlockLink_t structure immediately - before it. */ - puc -= xHeapStructSize; - - /* This casting is to keep the compiler from issuing warnings. */ - voidp = (void *) puc; - pxLink = (BlockLink_t *) voidp; - - /* Check if the block is actually allocated. */ - configASSERT((pxLink->xBlockSize & xBlockAllocatedBit) != 0); - configASSERT(pxLink->pxNextFreeBlock == NULL); - - sz = (pxLink->xBlockSize & ~xBlockAllocatedBit) - xHeapStructSize; - } - (void) xTaskResumeAll(); - } - - return sz; -} - -void * __wrap_malloc(size_t size) -{ - return pvPortMalloc(size); -} - -void __wrap_free(void * ptr) -{ - vPortFree(ptr); -} - -void * __wrap_calloc(size_t num, size_t size) -{ - size_t total_size = num * size; - - // Handle overflow from (num * size) - if ((size != 0) && ((total_size / size) != num)) - { - return nullptr; - } - - void * ptr = pvPortMalloc(total_size); - if (ptr) - { - memset(ptr, 0, total_size); - } - else - { - ChipLogError(DeviceLayer, "__wrap_calloc: Could not allocate memory!"); - } - - return ptr; -} - -void * __wrap_realloc(void * ptr, size_t new_size) -{ - - void * new_ptr = NULL; - - if (new_size) - { - size_t old_ptr_size = xPortMallocUsableSize(ptr); - if (new_size <= old_ptr_size) - { - /* Return old pointer if the newly allocated size is smaller - or equal to the allocated size for old_ptr */ - return ptr; - } - - /* if old_ptr is NULL, then old_ptr_size is zero and new_ptr will be returned */ - new_ptr = pvPortMalloc(new_size); - - if (!new_ptr) - { - ChipLogError(DeviceLayer, "__wrap_realloc: Could not allocate memory!"); - return NULL; - } - - memset(reinterpret_cast(new_ptr) + old_ptr_size, 0, (new_size - old_ptr_size)); - memcpy(new_ptr, ptr, old_ptr_size); - } - - vPortFree(ptr); - - return new_ptr; -} - -void * __wrap__malloc_r(void * REENT, size_t size) -{ - return __wrap_malloc(size); -} - -void __wrap__free_r(void * REENT, void * ptr) -{ - __wrap_free(ptr); -} - -void * __wrap__realloc_r(void * REENT, void * ptr, size_t new_size) -{ - return __wrap_realloc(ptr, new_size); -} - -} // extern "C" diff --git a/examples/platform/nxp/k32w/k32w0/args.gni b/examples/platform/nxp/k32w/k32w0/args.gni deleted file mode 100644 index 5af5e1d18b3123..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/args.gni +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright (c) 2020 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("//build_overrides/chip.gni") - -import("${chip_root}/src/platform/nxp/k32w/k32w0/args.gni") - -openthread_core_config_deps = [] -openthread_core_config_deps = [ "${chip_root}/examples/platform/nxp/k32w/k32w0:openthread_core_config_k32w0_chip_examples" ] - -chip_ble_project_config_include = "" -chip_device_project_config_include = "" -chip_project_config_include = "" -chip_inet_project_config_include = "" -chip_system_project_config_include = "" - -chip_system_config_provide_statistics = false -chip_with_nlfaultinjection = true - -chip_system_config_use_open_thread_inet_endpoints = true -chip_with_lwip = false diff --git a/examples/platform/nxp/k32w/k32w0/common/CustomFactoryDataProvider.cpp b/examples/platform/nxp/k32w/k32w0/common/CustomFactoryDataProvider.cpp deleted file mode 100644 index 7f2f6d9bc0cad0..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/common/CustomFactoryDataProvider.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Copyright (c) 2022 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. - */ - -#include "CustomFactoryDataProvider.h" - -namespace chip { -namespace DeviceLayer { - -static constexpr size_t kMaxLengthCustomId1 = 10; -static constexpr size_t kMaxLengthCustomId2 = 50; -static constexpr size_t kMaxLengthCustomId3 = 100; - -CustomFactoryDataProvider::CustomFactoryDataProvider() -{ - // Custom ids should be from a range that does not overlap with the standard factory data range. - static_assert((uint16_t) CustomFactoryIds::kCustomId1 >= (uint16_t) FactoryDataProvider::FactoryDataId::kMaxId); -} - -CHIP_ERROR CustomFactoryDataProvider::ParseFunctionExample() -{ - uint8_t data_buf[kMaxLengthCustomId1]; - MutableByteSpan buffer(data_buf); - memset(buffer.data(), 0, buffer.size()); - uint16_t userDataSize = 0; - // A user can use FactoryDataProvider::SearchForId to read an id from internal - // flash factory data section. - auto * provider = static_cast(DeviceLayer::GetDeviceInstanceInfoProvider()); - ReturnErrorOnFailure((provider != nullptr) ? CHIP_NO_ERROR : CHIP_ERROR_INVALID_ADDRESS); - ReturnErrorOnFailure(provider->SearchForId(CustomFactoryIds::kCustomId1, buffer.data(), buffer.size(), userDataSize)); - - // Data should now be ready for custom parsing. - - return CHIP_NO_ERROR; -} - -} // namespace DeviceLayer -} // namespace chip diff --git a/examples/platform/nxp/k32w/k32w0/common/CustomFactoryDataProvider.h b/examples/platform/nxp/k32w/k32w0/common/CustomFactoryDataProvider.h deleted file mode 100644 index dfb722d67fdc11..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/common/CustomFactoryDataProvider.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * Copyright (c) 2022 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. - */ -#pragma once - -#include - -namespace chip { -namespace DeviceLayer { - -/** - * @brief This is an example class that extends the platform factory data provider - * to support custom functionality. Users should implement their own custom - * provider based on this example. - */ - -class CustomFactoryDataProvider -{ -public: - /* Custom IDs should start from at least FactoryDataId::kMaxId, which is - * the next available valid ID. Last default ID is kMaxId - 1. - */ - enum CustomFactoryIds - { - kCustomId1 = 200, // Random id that is greater than FactoryDataId::kMaxId. - kCustomId2, - kCustomId3, - kCustomMaxId - }; - - CustomFactoryDataProvider(); - - /* Declare here custom functions to be implemented. */ - CHIP_ERROR ParseFunctionExample(); -}; - -} // namespace DeviceLayer -} // namespace chip diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/ssbl_bin.JPG b/examples/platform/nxp/k32w/k32w0/doc/images/ssbl_bin.JPG deleted file mode 100644 index fb871d45aeb5f98f646d44beed6819c14eb87cc9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45572 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

    G^k2O*s2mrL0`Y)7PQbm=4?yBI0yR7;M{ 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

    gOi$J=+rj#`=uYE6{J>CtMBGOUQuraQf`;L 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 diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/ssbl_select.JPG b/examples/platform/nxp/k32w/k32w0/doc/images/ssbl_select.JPG deleted file mode 100644 index 79ea51b62698e85ebbb68dbc66abf9097e02ba4b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107428 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 diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/ssbl_simple_hash.JPG b/examples/platform/nxp/k32w/k32w0/doc/images/ssbl_simple_hash.JPG deleted file mode 100755 index 9ec701b0bb1d86cac72c2df63702fde227d33f77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56397 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 z 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 /dev/null) && (dos2unix " + sign_images_path + ")", shell=True) - - # Call sign_images.sh script with the output directory - cmd = sign_images_path + " " + os.getcwd() - if args.simple_hash: - cmd = cmd + " -SimpleHashVerification" - - subprocess.call(cmd, shell=True) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument( - "--simple-hash", - help="When enabled, adds a hash of the whole image at the end of the binary.", - action="store_true" - ) - args = parser.parse_args() - - main(args) diff --git a/examples/platform/nxp/k32w/k32w0/util/LEDWidget.cpp b/examples/platform/nxp/k32w/k32w0/util/LEDWidget.cpp deleted file mode 100644 index fec3a5b0afca70..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/util/LEDWidget.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * All rights reserved. - * - * 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. - */ - -#include "LEDWidget.h" - -#include - -void LEDWidget::Init(LED_t led) -{ - mLastChangeTimeMS = 0; - mBlinkOnTimeMS = 0; - mBlinkOffTimeMS = 0; - mGPIONum = led; - mState = false; - - Set(false); -} - -void LEDWidget::Invert(void) -{ - Set(!mState); -} - -void LEDWidget::Set(bool state) -{ - mLastChangeTimeMS = mBlinkOnTimeMS = mBlinkOffTimeMS = 0; - DoSet(state); -} - -void LEDWidget::Blink(uint32_t changeRateMS) -{ - Blink(changeRateMS, changeRateMS); -} - -void LEDWidget::Blink(uint32_t onTimeMS, uint32_t offTimeMS) -{ - mBlinkOnTimeMS = onTimeMS; - mBlinkOffTimeMS = offTimeMS; - Animate(); -} - -void LEDWidget::Animate() -{ - if (mBlinkOnTimeMS != 0 && mBlinkOffTimeMS != 0) - { - uint64_t nowMS = chip::System::SystemClock().GetMonotonicMilliseconds64().count(); - uint64_t stateDurMS = mState ? mBlinkOnTimeMS : mBlinkOffTimeMS; - uint64_t nextChangeTimeMS = mLastChangeTimeMS + stateDurMS; - - if (nextChangeTimeMS < nowMS) - { - DoSet(!mState); - mLastChangeTimeMS = nowMS; - } - } -} - -void LEDWidget::DoSet(bool state) -{ - mState = state; - - if (state) - { - LED_TurnOnLed(mGPIONum); - } - else - { - LED_TurnOffLed(mGPIONum); - } -} diff --git a/examples/platform/nxp/k32w/k32w0/util/include/LEDWidget.h b/examples/platform/nxp/k32w/k32w0/util/include/LEDWidget.h deleted file mode 100644 index f725eeaa9d74f5..00000000000000 --- a/examples/platform/nxp/k32w/k32w0/util/include/LEDWidget.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * Copyright (c) 2020 Google LLC. - * All rights reserved. - * - * 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. - */ - -#include "LED.h" - -#pragma once - -class LEDWidget -{ -public: - void Init(LED_t gpioNum); - void Set(bool state); - void Invert(void); - void Blink(uint32_t changeRateMS); - void Blink(uint32_t onTimeMS, uint32_t offTimeMS); - void Animate(); - -private: - uint64_t mLastChangeTimeMS; - uint32_t mBlinkOnTimeMS; - uint32_t mBlinkOffTimeMS; - LED_t mGPIONum; - bool mState; - - void DoSet(bool state); -}; diff --git a/examples/platform/nxp/k32w/k32w0/common/README.md b/examples/platform/nxp/k32w0/doc/CustomFactoryDataProvider.md similarity index 100% rename from examples/platform/nxp/k32w/k32w0/common/README.md rename to examples/platform/nxp/k32w0/doc/CustomFactoryDataProvider.md diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/chiptool_main_screen.png b/examples/platform/nxp/k32w0/doc/images/chiptool_main_screen.png similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/chiptool_main_screen.png rename to examples/platform/nxp/k32w0/doc/images/chiptool_main_screen.png diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/flash_location.JPG b/examples/platform/nxp/k32w0/doc/images/flash_location.JPG similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/flash_location.JPG rename to examples/platform/nxp/k32w0/doc/images/flash_location.JPG diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/form_web.JPG b/examples/platform/nxp/k32w0/doc/images/form_web.JPG similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/form_web.JPG rename to examples/platform/nxp/k32w0/doc/images/form_web.JPG diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/k32w-dk6-connectors.jpg b/examples/platform/nxp/k32w0/doc/images/k32w-dk6-connectors.jpg similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/k32w-dk6-connectors.jpg rename to examples/platform/nxp/k32w0/doc/images/k32w-dk6-connectors.jpg diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/k32w-dk6.jpg b/examples/platform/nxp/k32w0/doc/images/k32w-dk6.jpg similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/k32w-dk6.jpg rename to examples/platform/nxp/k32w0/doc/images/k32w-dk6.jpg diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/k32w-se.jpg b/examples/platform/nxp/k32w0/doc/images/k32w-se.jpg similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/k32w-se.jpg rename to examples/platform/nxp/k32w0/doc/images/k32w-se.jpg diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/mcux-sdk-download.JPG b/examples/platform/nxp/k32w0/doc/images/mcux-sdk-download.JPG similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/mcux-sdk-download.JPG rename to examples/platform/nxp/k32w0/doc/images/mcux-sdk-download.JPG diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/nxp_hw_connectivity.JPG b/examples/platform/nxp/k32w0/doc/images/nxp_hw_connectivity.JPG similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/nxp_hw_connectivity.JPG rename to examples/platform/nxp/k32w0/doc/images/nxp_hw_connectivity.JPG diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/on_off_cluster.png b/examples/platform/nxp/k32w0/doc/images/on_off_cluster.png similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/on_off_cluster.png rename to examples/platform/nxp/k32w0/doc/images/on_off_cluster.png diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/ota_topology.JPG b/examples/platform/nxp/k32w0/doc/images/ota_topology.JPG similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/ota_topology.JPG rename to examples/platform/nxp/k32w0/doc/images/ota_topology.JPG diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/pdm_ext_flash.JPG b/examples/platform/nxp/k32w0/doc/images/pdm_ext_flash.JPG similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/pdm_ext_flash.JPG rename to examples/platform/nxp/k32w0/doc/images/pdm_ext_flash.JPG diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/power_conf.JPG b/examples/platform/nxp/k32w0/doc/images/power_conf.JPG similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/power_conf.JPG rename to examples/platform/nxp/k32w0/doc/images/power_conf.JPG diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/power_view.JPG b/examples/platform/nxp/k32w0/doc/images/power_view.JPG similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/power_view.JPG rename to examples/platform/nxp/k32w0/doc/images/power_view.JPG diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/select-sdk.JPG b/examples/platform/nxp/k32w0/doc/images/select-sdk.JPG similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/select-sdk.JPG rename to examples/platform/nxp/k32w0/doc/images/select-sdk.JPG diff --git a/examples/platform/nxp/k32w/k32w0/doc/images/thread_credentials.png b/examples/platform/nxp/k32w0/doc/images/thread_credentials.png similarity index 100% rename from examples/platform/nxp/k32w/k32w0/doc/images/thread_credentials.png rename to examples/platform/nxp/k32w0/doc/images/thread_credentials.png diff --git a/gn_build.sh b/gn_build.sh index 9f6c76571da593..e9110442a52293 100755 --- a/gn_build.sh +++ b/gn_build.sh @@ -164,7 +164,7 @@ if [[ ! -d "$NXP_K32W0_SDK_ROOT" ]]; then echo "Hint: Set \$NXP_K32W0_SDK_ROOT to enable building for K32W061" else echo 'To build the K32W lock sample as a standalone project': - echo "(cd $CHIP_ROOT/examples/lock-app/nxp/k32w/k32w0; gn gen out/debug --args='$k32w_sdk_args'; ninja -C out/debug)" + echo "(cd $CHIP_ROOT/examples/lock-app/nxp/k32w0; gn gen out/debug --args='$k32w_sdk_args'; ninja -C out/debug)" fi echo diff --git a/scripts/build/builders/nxp.py b/scripts/build/builders/nxp.py index b72015f0afc677..e119a78b5e2cc2 100644 --- a/scripts/build/builders/nxp.py +++ b/scripts/build/builders/nxp.py @@ -54,7 +54,7 @@ def Name(self, os_env): def FolderName(self, os_env): if self == NxpBoard.K32W0: - return 'k32w/k32w0' + return 'k32w0' elif self == NxpBoard.K32W1: return 'k32w/k32w1' elif self == NxpBoard.RW61X: diff --git a/scripts/setup/requirements.nxp.txt b/scripts/setup/requirements.nxp.txt index a78e1f0fc6230d..615e170ce83ce4 100644 --- a/scripts/setup/requirements.nxp.txt +++ b/scripts/setup/requirements.nxp.txt @@ -1,4 +1,3 @@ crc>=7.0.0 jsonschema>=4.17.0 -pycrypto>=2.6.1 pycryptodome>=3.20.0 diff --git a/src/platform/nxp/common/legacy/BLEManagerCommon.cpp b/src/platform/nxp/common/legacy/BLEManagerCommon.cpp new file mode 100644 index 00000000000000..d9dbde88f3a614 --- /dev/null +++ b/src/platform/nxp/common/legacy/BLEManagerCommon.cpp @@ -0,0 +1,1435 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * Copyright (c) 2020 Nest Labs, Inc. + * All rights reserved. + * + * 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. + */ + +/** + * @file + * Provides an implementation of the BLEManager singleton object + * for the K32W platforms. + */ + +/* this file behaves like a config.h, comes first */ +#include + +#include + +#include + +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + +#include + +#include "board.h" +#include "gatt_db_app_interface.h" +#include "gatt_db_handles.h" +#include "stdio.h" +#include "timers.h" + +#if defined(CPU_JN518X) && defined(chip_with_low_power) && (chip_with_low_power == 1) +#include "PWR_Configuration.h" +#endif + +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING +#include +#include +#endif + +/******************************************************************************* + * Local data types + *******************************************************************************/ +extern "C" bool_t Ble_ConfigureHostStackConfig(void); + +#if defined(chip_with_low_power) && (chip_with_low_power == 1) +extern "C" void PWR_DisallowDeviceToSleep(void); +extern "C" void PWR_AllowDeviceToSleep(void); +#endif + +using namespace ::chip; +using namespace ::chip::Ble; + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +namespace { +/******************************************************************************* + * Macros & Constants definitions + *******************************************************************************/ +/* Timeout of BLE commands */ +#define CHIP_BLE_KW_EVNT_TIMEOUT 1000 / portTICK_PERIOD_MS + +/** BLE advertisement state changed */ +#define CHIP_BLE_KW_EVNT_ADV_CHANGED 0x0001 +/** BLE advertisement command failed */ +#define CHIP_BLE_KW_EVNT_ADV_FAILED 0x0002 +/** BLE advertisement setup failed */ +#define CHIP_BLE_KW_EVNT_ADV_SETUP_FAILED 0x0004 +/** BLE advertisement parameters setup complete */ +#define CHIP_BLE_KW_EVNT_ADV_PAR_SETUP_COMPLETE 0x0008 +/** BLE advertisement data setup complete */ +#define CHIP_BLE_KW_EVNT_ADV_DAT_SETUP_COMPLETE 0x0010 +/** BLE random address set */ +#define CHIP_BLE_KW_EVNT_RND_ADDR_SET 0x0020 +/** BLE Initialization complete */ +#define CHIP_BLE_KW_EVNT_INIT_COMPLETE 0x0040 +/** BLE Received a handle value confirmation from the client */ +#define CHIP_BLE_KW_EVNT_INDICATION_CONFIRMED 0x0080 +/** BLE send indication failed */ +#define CHIP_BLE_KW_EVNT_INDICATION_FAILED 0x0100 +/** TX Power Level Set */ +#define CHIP_BLE_KW_EVNT_POWER_LEVEL_SET 0x0200 +/** Maximal time of connection without activity */ +#define CHIP_BLE_KW_CONN_TIMEOUT 60000 +/** Maximum number of pending BLE events */ +#define CHIP_BLE_EVENT_QUEUE_MAX_ENTRIES 10 + +#define LOOP_EV_BLE (0x08) + +/* controller task configuration */ +#define CONTROLLER_TASK_PRIORITY (6U) +#define CONTROLLER_TASK_STACK_SIZE (gControllerTaskStackSize_c / sizeof(StackType_t)) + +/* host task configuration */ +#define HOST_TASK_PRIORITY (4U) +#define HOST_TASK_STACK_SIZE (gHost_TaskStackSize_c / sizeof(StackType_t)) + +/* advertising configuration */ +#define BLEKW_ADV_MAX_NO (2) +#define BLEKW_SCAN_RSP_MAX_NO (2) +#define BLEKW_MAX_ADV_DATA_LEN (31) +#define CHIP_ADV_SHORT_UUID_LEN (2) + +/* FreeRTOS sw timer */ +TimerHandle_t sbleAdvTimeoutTimer; + +/* Queue used to synchronize asynchronous messages from the KW BLE tasks */ +QueueHandle_t sBleEventQueue; + +/* Used to manage asynchronous events from BLE Stack: e.g.: GAP setup finished */ +EventGroupHandle_t sEventGroup; + +TimerHandle_t connectionTimeout; + +const uint8_t ShortUUID_CHIPoBLEService[] = { 0xF6, 0xFF }; + +#if defined(chip_with_low_power) && (chip_with_low_power == 1) +static bool bleAppStopInProgress; +#endif + +BLEManagerCommon * sImplInstance = nullptr; + +} // namespace + +CHIP_ERROR BLEManagerCommon::_Init() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + EventBits_t eventBits; + uint16_t attChipRxHandle[1] = { (uint16_t) value_chipoble_rx }; + +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + uint16_t attChipC3Handle[1] = { (uint16_t) value_chipoble_c3 }; +#endif + + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; + + // Check if BLE stack is initialized + VerifyOrExit(!mFlags.Has(Flags::kK32WBLEStackInitialized), err = CHIP_ERROR_INCORRECT_STATE); + + // Initialize the Chip BleLayer. + err = BleLayer::Init(this, this, &DeviceLayer::SystemLayer()); + SuccessOrExit(err); + + /* Initialization of message wait events - + * used for receiving BLE Stack events */ + sEventGroup = xEventGroupCreate(); + VerifyOrExit(sEventGroup != NULL, err = CHIP_ERROR_INCORRECT_STATE); + + /* Prepare callback input queue.*/ + sBleEventQueue = xQueueCreate(CHIP_BLE_EVENT_QUEUE_MAX_ENTRIES, sizeof(blekw_msg_t *)); + VerifyOrExit(sBleEventQueue != NULL, err = CHIP_ERROR_INCORRECT_STATE); + + /* Create the connection timeout timer. */ + connectionTimeout = + xTimerCreate("bleTimeoutTmr", pdMS_TO_TICKS(CHIP_BLE_KW_CONN_TIMEOUT), pdFALSE, (void *) 0, blekw_connection_timeout_cb); + VerifyOrExit(connectionTimeout != NULL, err = CHIP_ERROR_INCORRECT_STATE); + + sImplInstance = GetImplInstance(); + + /* BLE platform code initialization */ + SuccessOrExit(err = InitHostController(&blekw_generic_cb)); + + /* Register the GATT server callback */ + VerifyOrExit(GattServer_RegisterCallback(blekw_gatt_server_cb) == gBleSuccess_c, err = CHIP_ERROR_INCORRECT_STATE); + + /* Wait until BLE Stack is ready */ + eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_INIT_COMPLETE, pdTRUE, pdTRUE, CHIP_BLE_KW_EVNT_TIMEOUT); + VerifyOrExit(eventBits & CHIP_BLE_KW_EVNT_INIT_COMPLETE, err = CHIP_ERROR_INCORRECT_STATE); + +#if BLE_HIGH_TX_POWER + /* Set Adv Power */ + Gap_SetTxPowerLevel(gAdvertisingPowerLeveldBm_c, gTxPowerAdvChannel_c); + eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_POWER_LEVEL_SET, pdTRUE, pdTRUE, CHIP_BLE_KW_EVNT_TIMEOUT); + VerifyOrExit(eventBits & CHIP_BLE_KW_EVNT_POWER_LEVEL_SET, err = CHIP_ERROR_INCORRECT_STATE); + + /* Set Connect Power */ + Gap_SetTxPowerLevel(gConnectPowerLeveldBm_c, gTxPowerConnChannel_c); + eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_POWER_LEVEL_SET, pdTRUE, pdTRUE, CHIP_BLE_KW_EVNT_TIMEOUT); + VerifyOrExit(eventBits & CHIP_BLE_KW_EVNT_POWER_LEVEL_SET, err = CHIP_ERROR_INCORRECT_STATE); +#endif + +#if defined(CPU_JN518X) && defined(chip_with_low_power) && (chip_with_low_power == 1) + PWR_ChangeDeepSleepMode(cPWR_PowerDown_RamRet); +#endif + + GattServer_RegisterHandlesForWriteNotifications(1, attChipRxHandle); +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + VerifyOrExit(GattServer_RegisterHandlesForReadNotifications(1, attChipC3Handle) == gBleSuccess_c, + err = CHIP_ERROR_INCORRECT_STATE); +#endif + + mFlags.Set(Flags::kK32WBLEStackInitialized); + mFlags.Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART ? true : false); + mFlags.Set(Flags::kFastAdvertisingEnabled); + + // Create FreeRTOS sw timer for BLE timeouts and interval change. + sbleAdvTimeoutTimer = xTimerCreate("BleAdvTimer", // Just a text name, not used by the RTOS kernel + pdMS_TO_TICKS(100), // == default timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = ble obj context + BleAdvTimeoutHandler // timer callback handler + ); + VerifyOrExit(sbleAdvTimeoutTimer != NULL, err = CHIP_ERROR_INCORRECT_STATE); + +exit: + return err; +} + +uint16_t BLEManagerCommon::_NumConnections(void) +{ + return static_cast(mDeviceConnected == true); +} + +bool BLEManagerCommon::_IsAdvertisingEnabled(void) +{ + return mFlags.Has(Flags::kAdvertisingEnabled); +} + +bool BLEManagerCommon::_IsAdvertising(void) +{ + return mFlags.Has(Flags::kAdvertising); +} + +CHIP_ERROR BLEManagerCommon::_SetAdvertisingEnabled(bool val) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE); + + if (mFlags.Has(Flags::kAdvertisingEnabled) != val) + { + mFlags.Set(Flags::kAdvertisingEnabled, val); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + } + +exit: + return err; +} + +CHIP_ERROR BLEManagerCommon::_SetAdvertisingMode(BLEAdvertisingMode mode) +{ + switch (mode) + { + case BLEAdvertisingMode::kFastAdvertising: + mFlags.Set(Flags::kFastAdvertisingEnabled); + break; + case BLEAdvertisingMode::kSlowAdvertising: { + // We are in FreeRTOS timer service context, which is a default daemon task and has + // the highest priority. Stop advertising should be scheduled to run from Matter task. + mFlags.Clear(Flags::kFastAdvertisingEnabled); + PlatformMgr().ScheduleWork(StopAdvertisingPriorToSwitchingMode, 0); + break; + } + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + mFlags.Set(Flags::kRestartAdvertising); + PlatformMgr().ScheduleWork(DriveBLEState, 0); + return CHIP_NO_ERROR; +} + +CHIP_ERROR BLEManagerCommon::_GetDeviceName(char * buf, size_t bufSize) +{ + if (strlen(mDeviceName) >= bufSize) + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + strcpy(buf, mDeviceName); + return CHIP_NO_ERROR; +} + +CHIP_ERROR BLEManagerCommon::_SetDeviceName(const char * deviceName) +{ + if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_NotSupported) + { + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; + } + if (deviceName != NULL && deviceName[0] != 0) + { + if (strlen(deviceName) >= kMaxDeviceNameLength) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + memset(mDeviceName, 0, kMaxDeviceNameLength); + strcpy(mDeviceName, deviceName); + mFlags.Set(Flags::kDeviceNameSet); + ChipLogProgress(DeviceLayer, "Setting device name to : \"%s\"", deviceName); + } + else + { + mDeviceName[0] = 0; + mFlags.Clear(Flags::kDeviceNameSet); + } + + return CHIP_NO_ERROR; +} + +void BLEManagerCommon::_OnPlatformEvent(const ChipDeviceEvent * event) +{ + switch (event->Type) + { + case DeviceEventType::kCHIPoBLESubscribe: + ChipDeviceEvent connEstEvent; + + HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); + connEstEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished; + PlatformMgr().PostEventOrDie(&connEstEvent); + break; + + case DeviceEventType::kCHIPoBLEUnsubscribe: + HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); + break; + + case DeviceEventType::kCHIPoBLEWriteReceived: + HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_1_UUID, + PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data)); + break; + + case DeviceEventType::kCHIPoBLEConnectionError: + HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason); + break; + + case DeviceEventType::kCHIPoBLEIndicateConfirm: + HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &Ble::CHIP_BLE_CHAR_2_UUID); + break; + + default: + break; + } +} + +CHIP_ERROR BLEManagerCommon::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, + const ChipBleUUID * charId) +{ + ChipLogProgress(DeviceLayer, "BLEManagerCommon::SubscribeCharacteristic() not supported"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR BLEManagerCommon::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, + const ChipBleUUID * charId) +{ + ChipLogProgress(DeviceLayer, "BLEManagerCommon::UnsubscribeCharacteristic() not supported"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR BLEManagerCommon::CloseConnection(BLE_CONNECTION_OBJECT conId) +{ + return blekw_stop_connection_internal(conId); +} + +uint16_t BLEManagerCommon::GetMTU(BLE_CONNECTION_OBJECT conId) const +{ + uint16_t tempMtu = 0; + (void) Gatt_GetMtu(conId, &tempMtu); + + return tempMtu; +} + +CHIP_ERROR BLEManagerCommon::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle pBuf) +{ + ChipLogProgress(DeviceLayer, "BLEManagerCommon::SendWriteRequest() not supported"); + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +void BLEManagerCommon::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) +{ + BLEMgrImpl().CloseConnection(conId); +} + +CHIP_ERROR BLEManagerCommon::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId, + PacketBufferHandle data) +{ + VerifyOrReturnError(UUIDsMatch(&Ble::CHIP_BLE_CHAR_2_UUID, charId), BLE_ERROR_GATT_WRITE_FAILED); + + CHIP_ERROR err = CHIP_NO_ERROR; + + if (blekw_send_event(conId, value_chipoble_tx, data->Start(), data->DataLength()) != BLE_OK) + { + err = CHIP_ERROR_SENDING_BLOCKED; + } + else + { + ChipDeviceEvent event; + event.Type = DeviceEventType::kCHIPoBLEIndicateConfirm; + event.CHIPoBLEIndicateConfirm.ConId = conId; + err = PlatformMgr().PostEvent(&event); + } + + return err; +} + +BLEManagerCommon::ble_err_t BLEManagerCommon::blekw_send_event(int8_t connection_handle, uint16_t handle, uint8_t * data, + uint32_t len) +{ + EventBits_t eventBits; + +#if CHIP_DEVICE_CHIP0BLE_DEBUG + ChipLogProgress(DeviceLayer, "Trying to send event."); +#endif + + if (connection_handle < 0 || handle <= 0) + { + ChipLogProgress(DeviceLayer, "BLE Event - Bad Handle"); + return BLE_E_FAIL; + } + + if (len > 0 && data == NULL) + { + ChipLogProgress(DeviceLayer, "BLE Event - Invalid Data"); + return BLE_E_FAIL; + } + + /************* Send the indication *************/ + xEventGroupClearBits(sEventGroup, CHIP_BLE_KW_EVNT_INDICATION_CONFIRMED | CHIP_BLE_KW_EVNT_INDICATION_FAILED); + + if (GattServer_SendInstantValueIndication(connection_handle, handle, len, data) != gBleSuccess_c) + { + ChipLogProgress(DeviceLayer, "BLE Event - Can't sent indication"); + return BLE_E_FAIL; + } + + /* Wait until BLE Stack is ready */ + eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_INDICATION_CONFIRMED | CHIP_BLE_KW_EVNT_INDICATION_FAILED, pdTRUE, + pdFALSE, CHIP_BLE_KW_EVNT_TIMEOUT); + + if (eventBits & CHIP_BLE_KW_EVNT_INDICATION_FAILED) + { + ChipLogProgress(DeviceLayer, "BLE Event - Sent Failed"); + return BLE_E_FAIL; + } + +#if CHIP_DEVICE_CHIP0BLE_DEBUG + ChipLogProgress(DeviceLayer, "BLE Event - Sent :-) "); +#endif + + return BLE_OK; +} +/******************************************************************************* + * Private functions + *******************************************************************************/ + +BLEManagerCommon::ble_err_t BLEManagerCommon::blekw_start_advertising(gapAdvertisingParameters_t * adv_params, + gapAdvertisingData_t * adv, gapScanResponseData_t * scnrsp) +{ + EventBits_t eventBits; + + /************* Set the advertising parameters *************/ + xEventGroupClearBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_SETUP_FAILED | CHIP_BLE_KW_EVNT_ADV_PAR_SETUP_COMPLETE); + + /* Set the advertising parameters */ + if (Gap_SetAdvertisingParameters(adv_params) != gBleSuccess_c) + { + vTaskDelay(1); + + /* Retry, just to make sure before giving up and sending an error. */ + if (Gap_SetAdvertisingParameters(adv_params) != gBleSuccess_c) + { + return BLE_E_SET_ADV_PARAMS; + } + } + + eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_SETUP_FAILED | CHIP_BLE_KW_EVNT_ADV_PAR_SETUP_COMPLETE, + pdTRUE, pdFALSE, CHIP_BLE_KW_EVNT_TIMEOUT); + + if (!(eventBits & CHIP_BLE_KW_EVNT_ADV_PAR_SETUP_COMPLETE)) + { + return BLE_E_ADV_PARAMS_FAILED; + } + + /************* Set the advertising data *************/ + xEventGroupClearBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_SETUP_FAILED | CHIP_BLE_KW_EVNT_ADV_DAT_SETUP_COMPLETE); + + /* Set the advertising data */ + if (Gap_SetAdvertisingData(adv, scnrsp) != gBleSuccess_c) + { + return BLE_E_SET_ADV_DATA; + } + + eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_SETUP_FAILED | CHIP_BLE_KW_EVNT_ADV_DAT_SETUP_COMPLETE, + pdTRUE, pdFALSE, CHIP_BLE_KW_EVNT_TIMEOUT); + + if (!(eventBits & CHIP_BLE_KW_EVNT_ADV_DAT_SETUP_COMPLETE)) + { + return BLE_E_ADV_SETUP_FAILED; + } + + /************* Start the advertising *************/ + xEventGroupClearBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_CHANGED | CHIP_BLE_KW_EVNT_ADV_FAILED); + + if (gBleSuccess_c != Gap_CreateRandomDeviceAddress(NULL, NULL)) + { + return BLE_E_SET_ADV_PARAMS; + } + + eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_RND_ADDR_SET, pdTRUE, pdTRUE, CHIP_BLE_KW_EVNT_TIMEOUT); + + if (!(eventBits & CHIP_BLE_KW_EVNT_RND_ADDR_SET)) + { + return BLE_E_ADV_PARAMS_FAILED; + } + + /* Start the advertising */ + if (Gap_StartAdvertising(blekw_gap_advertising_cb, blekw_gap_connection_cb) != gBleSuccess_c) + { + return BLE_E_START_ADV; + } + +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + PWR_DisallowDeviceToSleep(); +#endif + + eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_CHANGED | CHIP_BLE_KW_EVNT_ADV_FAILED, pdTRUE, pdFALSE, + CHIP_BLE_KW_EVNT_TIMEOUT); + if (!(eventBits & CHIP_BLE_KW_EVNT_ADV_CHANGED)) + { +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + PWR_AllowDeviceToSleep(); +#endif + return BLE_E_START_ADV_FAILED; + } + +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + PWR_AllowDeviceToSleep(); +#endif + + return BLE_OK; +} + +BLEManagerCommon::ble_err_t BLEManagerCommon::blekw_stop_advertising(void) +{ + EventBits_t eventBits; + bleResult_t res; + + xEventGroupClearBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_CHANGED | CHIP_BLE_KW_EVNT_ADV_FAILED); + + /* Stop the advertising data */ + res = Gap_StopAdvertising(); + if (res != gBleSuccess_c) + { + ChipLogProgress(DeviceLayer, "Failed to stop advertising %d", res); + return BLE_E_STOP; + } + + eventBits = xEventGroupWaitBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_CHANGED | CHIP_BLE_KW_EVNT_ADV_FAILED, pdTRUE, pdFALSE, + CHIP_BLE_KW_EVNT_TIMEOUT); + + if (eventBits & CHIP_BLE_KW_EVNT_ADV_FAILED) + { + ChipLogProgress(DeviceLayer, "Stop advertising flat out failed."); + return BLE_E_ADV_FAILED; + } + else if (!(eventBits & CHIP_BLE_KW_EVNT_ADV_CHANGED)) + { + ChipLogProgress(DeviceLayer, "Stop advertising event timeout."); + return BLE_E_ADV_CHANGED; + } + + return BLE_OK; +} + +CHIP_ERROR BLEManagerCommon::ConfigureAdvertisingData(void) +{ + ble_err_t err; + CHIP_ERROR chipErr; + uint16_t discriminator; + uint16_t advInterval = 0; + gapAdvertisingData_t adv = { 0 }; + gapAdStructure_t adv_data[BLEKW_ADV_MAX_NO] = { { 0 } }; + gapAdStructure_t scan_rsp_data[BLEKW_SCAN_RSP_MAX_NO] = { { 0 } }; + uint8_t advPayload[BLEKW_MAX_ADV_DATA_LEN] = { 0 }; + gapScanResponseData_t scanRsp = { 0 }; + gapAdvertisingParameters_t adv_params = { 0 }; + uint8_t chipAdvDataFlags = (gLeGeneralDiscoverableMode_c | gBrEdrNotSupported_c); + uint8_t chipOverBleService[2]; + ChipBLEDeviceIdentificationInfo mDeviceIdInfo = { 0 }; + uint8_t mDeviceIdInfoLength = 0; + + chipErr = GetCommissionableDataProvider()->GetSetupDiscriminator(discriminator); + if (chipErr != CHIP_NO_ERROR) + { + return chipErr; + } + + if (!mFlags.Has(Flags::kDeviceNameSet)) + { + memset(mDeviceName, 0, kMaxDeviceNameLength); + snprintf(mDeviceName, kMaxDeviceNameLength, "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator); + } + + /**************** Prepare advertising data *******************************************/ + adv.cNumAdStructures = BLEKW_ADV_MAX_NO; + + chipErr = ConfigurationMgr().GetBLEDeviceIdentificationInfo(mDeviceIdInfo); + SuccessOrExit(chipErr); + mDeviceIdInfoLength = sizeof(mDeviceIdInfo); + + if ((mDeviceIdInfoLength + CHIP_ADV_SHORT_UUID_LEN + 1) > BLEKW_MAX_ADV_DATA_LEN) + { + return CHIP_ERROR_INCORRECT_STATE; + } + + adv_data[0].length = 0x02; + adv_data[0].adType = gAdFlags_c; + adv_data[0].aData = (uint8_t *) (&chipAdvDataFlags); + + adv_data[1].length = static_cast(mDeviceIdInfoLength + CHIP_ADV_SHORT_UUID_LEN + 1); + adv_data[1].adType = gAdServiceData16bit_c; + memcpy(advPayload, ShortUUID_CHIPoBLEService, CHIP_ADV_SHORT_UUID_LEN); + memcpy(&advPayload[CHIP_ADV_SHORT_UUID_LEN], (void *) &mDeviceIdInfo, mDeviceIdInfoLength); + adv_data[1].aData = advPayload; + + adv.aAdStructures = adv_data; + +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + ReturnErrorOnFailure(EncodeAdditionalDataTlv()); +#endif + + /**************** Prepare scan response data *******************************************/ + scanRsp.cNumAdStructures = BLEKW_SCAN_RSP_MAX_NO; + + scan_rsp_data[0].length = static_cast(strlen(mDeviceName) + 1); + scan_rsp_data[0].adType = gAdCompleteLocalName_c; + scan_rsp_data[0].aData = (uint8_t *) mDeviceName; + + scan_rsp_data[1].length = sizeof(chipOverBleService) + 1; + scan_rsp_data[1].adType = gAdComplete16bitServiceList_c; + chipOverBleService[0] = ShortUUID_CHIPoBLEService[0]; + chipOverBleService[1] = ShortUUID_CHIPoBLEService[1]; + scan_rsp_data[1].aData = (uint8_t *) chipOverBleService; + + scanRsp.aAdStructures = scan_rsp_data; + + /**************** Prepare advertising parameters *************************************/ + if (mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + advInterval = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX; + } + else + { + advInterval = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX; + } + advInterval = (uint16_t) (advInterval * 0.625F); + + adv_params.minInterval = adv_params.maxInterval = advInterval; + adv_params.advertisingType = gAdvConnectableUndirected_c; + adv_params.ownAddressType = gBleAddrTypeRandom_c; + adv_params.peerAddressType = gBleAddrTypePublic_c; + memset(adv_params.peerAddress, 0, gcBleDeviceAddressSize_c); + adv_params.channelMap = (gapAdvertisingChannelMapFlags_t) (gAdvChanMapFlag37_c | gAdvChanMapFlag38_c | gAdvChanMapFlag39_c); + adv_params.filterPolicy = gProcessAll_c; + + err = blekw_start_advertising(&adv_params, &adv, &scanRsp); + if (err == BLE_OK) + { + ChipLogProgress(DeviceLayer, "Started Advertising at %d ms", advInterval); + } + else + { + ChipLogProgress(DeviceLayer, "Advertising error 0x%x!", err); + mFlags.Clear(Flags::kAdvertising); + return CHIP_ERROR_INCORRECT_STATE; + } + +exit: + return chipErr; +} + +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING +CHIP_ERROR BLEManagerCommon::EncodeAdditionalDataTlv() +{ + CHIP_ERROR err = CHIP_NO_ERROR; + BitFlags dataFields; + AdditionalDataPayloadGeneratorParams params; + +#if CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) + uint8_t rotatingDeviceIdUniqueId[ConfigurationManager::kRotatingDeviceIDUniqueIDLength] = {}; + MutableByteSpan rotatingDeviceIdUniqueIdSpan(rotatingDeviceIdUniqueId); + + err = DeviceLayer::GetDeviceInstanceInfoProvider()->GetRotatingDeviceIdUniqueId(rotatingDeviceIdUniqueIdSpan); + SuccessOrExit(err); + err = ConfigurationMgr().GetLifetimeCounter(params.rotatingDeviceIdLifetimeCounter); + SuccessOrExit(err); + params.rotatingDeviceIdUniqueId = rotatingDeviceIdUniqueIdSpan; + dataFields.Set(AdditionalDataFields::RotatingDeviceId); +#endif /* CHIP_ENABLE_ROTATING_DEVICE_ID && defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) */ + err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(params, sImplInstance->c3AdditionalDataBufferHandle, + dataFields); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data (%s)", __func__); + } + + return err; +} + +void BLEManagerCommon::HandleC3ReadRequest(blekw_msg_t * msg) +{ + bleResult_t result; + blekw_att_read_data_t * att_rd_data = (blekw_att_read_data_t *) msg->data.data; + deviceId_t deviceId = att_rd_data->device_id; + uint16_t handle = att_rd_data->handle; + uint16_t length = sImplInstance->c3AdditionalDataBufferHandle->DataLength(); + const uint8_t * data = (const uint8_t *) sImplInstance->c3AdditionalDataBufferHandle->Start(); + + result = GattDb_WriteAttribute(handle, length, data); + if (result != gBleSuccess_c) + { + ChipLogError(DeviceLayer, "Failed to write C3 characteristic: %d", result); + } + + result = GattServer_SendAttributeReadStatus(deviceId, handle, gAttErrCodeNoError_c); + if (result != gBleSuccess_c) + { + ChipLogError(DeviceLayer, "Failed to send response to C3 read request: %d", result); + } +} +#endif /* CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING */ + +CHIP_ERROR BLEManagerCommon::StartAdvertising(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + mFlags.Set(Flags::kAdvertising); + mFlags.Clear(Flags::kRestartAdvertising); + + if (mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + StartBleAdvTimeoutTimer(CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_TIMEOUT); + } + + err = ConfigureAdvertisingData(); + + if (err == CHIP_NO_ERROR) + /* schedule NFC emulation stop */ + { + ChipDeviceEvent advChange; + advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; + advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Started; + err = PlatformMgr().PostEvent(&advChange); + } + + return err; +} + +CHIP_ERROR BLEManagerCommon::StopAdvertising(void) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + + if (mFlags.Has(Flags::kAdvertising)) + { + mFlags.Clear(Flags::kAdvertising); + mFlags.Clear(Flags::kRestartAdvertising); + + if (!mDeviceConnected) + { + ble_err_t err = blekw_stop_advertising(); + VerifyOrReturnError(err == BLE_OK, CHIP_ERROR_INCORRECT_STATE); + CancelBleAdvTimeoutTimer(); + } + +#if CONFIG_CHIP_NFC_COMMISSIONING + /* schedule NFC emulation stop */ + ChipDeviceEvent advChange; + advChange.Type = DeviceEventType::kCHIPoBLEAdvertisingChange; + advChange.CHIPoBLEAdvertisingChange.Result = kActivity_Stopped; + error = PlatformMgr().PostEvent(&advChange); +#endif + } + + return error; +} + +void BLEManagerCommon::DriveBLEState(void) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + + // Check if BLE stack is initialized + VerifyOrExit(mFlags.Has(Flags::kK32WBLEStackInitialized), err = CHIP_ERROR_INCORRECT_STATE); + + // Start advertising if needed... + if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kAdvertisingEnabled)) + { + // Start/re-start advertising if not already started, or if there is a pending change + // to the advertising configuration. + if (!mFlags.Has(Flags::kAdvertising) || mFlags.Has(Flags::kRestartAdvertising)) + { + err = StartAdvertising(); + SuccessOrExit(err); + } + } + // Otherwise, stop advertising if it is enabled. + else if (mFlags.Has(Flags::kAdvertising)) + { + err = StopAdvertising(); + SuccessOrExit(err); + // Reset to fast advertising mode only if SetBLEAdvertisingEnabled(false) was called (usually from app). + mFlags.Set(Flags::kFastAdvertisingEnabled); + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err)); + mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled; + } +} + +void BLEManagerCommon::DriveBLEState(intptr_t arg) +{ + sImplInstance->DriveBLEState(); +} + +void BLEManagerCommon::StopAdvertisingPriorToSwitchingMode(intptr_t arg) +{ + if (CHIP_NO_ERROR != sImplInstance->StopAdvertising()) + { + ChipLogProgress(DeviceLayer, "Failed to stop advertising"); + } +} + +void BLEManagerCommon::DoBleProcessing(void) +{ + blekw_msg_t * msg = NULL; + + while ((xQueueReceive(sBleEventQueue, &msg, 0) == pdTRUE) && msg) + { + if (msg->type == BLE_KW_MSG_ERROR) + { + if (msg->data.u8 == BLE_KW_MSG_2M_UPGRADE_ERROR) + { + ChipLogProgress(DeviceLayer, + "Warning. BLE is using 1Mbps. Couldn't upgrade to 2Mbps, " + "maybe the peer is missing 2Mbps support."); + } + else + { + ChipLogProgress(DeviceLayer, "BLE Error: %d.\n", msg->data.u8); + } + } + else if (msg->type == BLE_KW_MSG_CONNECTED) + { + sImplInstance->HandleConnectEvent(msg); + } + else if (msg->type == BLE_KW_MSG_DISCONNECTED) + { + sImplInstance->HandleConnectionCloseEvent(msg); + } + else if (msg->type == BLE_KW_MSG_MTU_CHANGED) + { + blekw_start_connection_timeout(); + ChipLogProgress(DeviceLayer, "BLE MTU size has been changed to %d.", msg->data.u16); + } + else if (msg->type == BLE_KW_MSG_ATT_WRITTEN || msg->type == BLE_KW_MSG_ATT_LONG_WRITTEN || + msg->type == BLE_KW_MSG_ATT_CCCD_WRITTEN) + { + sImplInstance->HandleWriteEvent(msg); + } + else if (msg->type == BLE_KW_MSG_ATT_READ) + { +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + blekw_att_read_data_t * att_rd_data = (blekw_att_read_data_t *) msg->data.data; + if (value_chipoble_c3 == att_rd_data->handle) + sImplInstance->HandleC3ReadRequest(msg); +#endif + } + else if (msg->type == BLE_KW_MSG_FORCE_DISCONNECT) + { + sImplInstance->HandleForceDisconnect(); + } + + /* Free the message from the queue */ + free(msg); + msg = NULL; + } +} + +void BLEManagerCommon::RegisterAppCallbacks(BLECallbackDelegate::GapGenericCallback gapCallback, + BLECallbackDelegate::GattServerCallback gattCallback) +{ + callbackDelegate.gapCallback = gapCallback; + callbackDelegate.gattCallback = gattCallback; +} + +void BLEManagerCommon::HandleConnectEvent(blekw_msg_t * msg) +{ + uint8_t deviceId = msg->data.u8; + ChipLogProgress(DeviceLayer, "BLE is connected with device: %d.\n", deviceId); + +#if gClkUseFro32K && defined(chip_with_low_power) && (chip_with_low_power == 1) + PWR_DisallowDeviceToSleep(); +#endif + + mDeviceId = deviceId; + mDeviceConnected = true; + + blekw_start_connection_timeout(); + PlatformMgr().ScheduleWork(DriveBLEState, 0); +} + +void BLEManagerCommon::HandleConnectionCloseEvent(blekw_msg_t * msg) +{ + uint8_t deviceId = msg->data.u8; + ChipLogProgress(DeviceLayer, "BLE is disconnected with device: %d.\n", deviceId); + +#if gClkUseFro32K && defined(chip_with_low_power) && (chip_with_low_power == 1) + PWR_AllowDeviceToSleep(); +#endif + + mDeviceConnected = false; + + ChipDeviceEvent event; + event.Type = DeviceEventType::kCHIPoBLEConnectionClosed; + event.CHIPoBLEConnectionError.ConId = deviceId; + event.CHIPoBLEConnectionError.Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED; + + CancelBleAdvTimeoutTimer(); + + PlatformMgr().PostEventOrDie(&event); + mFlags.Set(Flags::kRestartAdvertising); + mFlags.Set(Flags::kFastAdvertisingEnabled); + PlatformMgr().ScheduleWork(DriveBLEState, 0); +} + +void BLEManagerCommon::HandleWriteEvent(blekw_msg_t * msg) +{ + blekw_att_written_data_t * att_wr_data = (blekw_att_written_data_t *) msg->data.data; + attErrorCode_t status = gAttErrCodeNoError_c; + +#if CHIP_DEVICE_CHIP0BLE_DEBUG + ChipLogProgress(DeviceLayer, "Attribute write request(device: %d,handle: %d).", att_wr_data->device_id, att_wr_data->handle); +#endif + + blekw_start_connection_timeout(); + + if (value_chipoble_rx == att_wr_data->handle) + { + sImplInstance->HandleRXCharWrite(msg); + } + else if (cccd_chipoble_tx == att_wr_data->handle) + { + sImplInstance->HandleTXCharCCCDWrite(msg); + } + + /* TODO: do we need to send the status also for CCCD_WRITTEN? */ + if (msg->type != BLE_KW_MSG_ATT_CCCD_WRITTEN) + { + bleResult_t res = GattServer_SendAttributeWrittenStatus(att_wr_data->device_id, att_wr_data->handle, status); + + if (res != gBleSuccess_c) + { + ChipLogProgress(DeviceLayer, "GattServer_SendAttributeWrittenStatus returned %d", res); + } + } +} + +void BLEManagerCommon::HandleTXCharCCCDWrite(blekw_msg_t * msg) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + blekw_att_written_data_t * att_wr_data = (blekw_att_written_data_t *) msg->data.data; + ChipDeviceEvent event; + + VerifyOrExit(att_wr_data->length != 0, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(att_wr_data->data != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + +#if CHIP_DEVICE_CHIP0BLE_DEBUG + ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", *att_wr_data->data ? "subscribe" : "unsubscribe"); +#endif + + if (*att_wr_data->data) + { + if (!mDeviceSubscribed) + { + mDeviceSubscribed = true; + event.Type = DeviceEventType::kCHIPoBLESubscribe; + event.CHIPoBLESubscribe.ConId = att_wr_data->device_id; + err = PlatformMgr().PostEvent(&event); + } + } + else + { + mDeviceSubscribed = false; + event.Type = DeviceEventType::kCHIPoBLEUnsubscribe; + event.CHIPoBLESubscribe.ConId = att_wr_data->device_id; + err = PlatformMgr().PostEvent(&event); + } + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "HandleTXCharCCCDWrite() failed: %s", ErrorStr(err)); + } +} + +void BLEManagerCommon::HandleRXCharWrite(blekw_msg_t * msg) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + System::PacketBufferHandle buf; + blekw_att_written_data_t * att_wr_data = (blekw_att_written_data_t *) msg->data.data; + + VerifyOrExit(att_wr_data->length != 0, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(att_wr_data->data != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + + // Copy the data to a PacketBuffer. + buf = System::PacketBufferHandle::NewWithData(att_wr_data->data, att_wr_data->length); + VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY); + +#if CHIP_DEVICE_CHIP0BLE_DEBUG + ChipLogDetail(DeviceLayer, + "Write request/command received for" + "CHIPoBLE RX characteristic (con %u, len %u)", + att_wr_data->device_id, buf->DataLength()); +#endif + + // Post an event to the CHIP queue to deliver the data into the CHIP stack. + { + ChipDeviceEvent event; + event.Type = DeviceEventType::kCHIPoBLEWriteReceived; + event.CHIPoBLEWriteReceived.ConId = att_wr_data->device_id; + event.CHIPoBLEWriteReceived.Data = std::move(buf).UnsafeRelease(); + err = PlatformMgr().PostEvent(&event); + } +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "HandleRXCharWrite() failed: %s", ErrorStr(err)); + } +} + +void BLEManagerCommon::HandleForceDisconnect() +{ + ChipLogProgress(DeviceLayer, "BLE connection timeout: Forcing disconnection."); + + /* Set the advertising parameters */ + if (Gap_Disconnect(mDeviceId) != gBleSuccess_c) + { + ChipLogProgress(DeviceLayer, "Gap_Disconnect() failed."); + } + +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + PWR_AllowDeviceToSleep(); +#endif +} + +/******************************************************************************* + * BLE stack callbacks + *******************************************************************************/ +void BLEManagerCommon::blekw_generic_cb(gapGenericEvent_t * pGenericEvent) +{ + /* Call BLE Conn Manager */ + BleConnManager_GenericEvent(pGenericEvent); + + if (sImplInstance && sImplInstance->callbackDelegate.gapCallback) + { + sImplInstance->callbackDelegate.gapCallback(pGenericEvent); + } + + switch (pGenericEvent->eventType) + { + case gInternalError_c: + /* Notify the CHIP that the BLE hardware report fail */ + ChipLogProgress(DeviceLayer, "BLE Internal Error: Code 0x%04X, Source 0x%08X, HCI OpCode %d.\n", + pGenericEvent->eventData.internalError.errorCode, pGenericEvent->eventData.internalError.errorSource, + pGenericEvent->eventData.internalError.hciCommandOpcode); + if ((gHciUnsupportedRemoteFeature_c == pGenericEvent->eventData.internalError.errorCode) && + (gLeSetPhy_c == pGenericEvent->eventData.internalError.errorSource)) + { + (void) blekw_msg_add_u8(BLE_KW_MSG_ERROR, BLE_KW_MSG_2M_UPGRADE_ERROR); + } + else + { + (void) blekw_msg_add_u8(BLE_KW_MSG_ERROR, BLE_INTERNAL_ERROR); + } + break; + + case gAdvertisingSetupFailed_c: + xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_SETUP_FAILED); + break; + + case gAdvertisingParametersSetupComplete_c: + xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_PAR_SETUP_COMPLETE); + break; + + case gAdvertisingDataSetupComplete_c: + xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_DAT_SETUP_COMPLETE); + break; + + case gRandomAddressReady_c: + Gap_SetRandomAddress(pGenericEvent->eventData.addrReady.aAddress); + break; + + case gRandomAddressSet_c: + xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_RND_ADDR_SET); + break; + +#if BLE_HIGH_TX_POWER + case gTxPowerLevelSetComplete_c: + if (gBleSuccess_c == pGenericEvent->eventData.txPowerLevelSetStatus) + { + xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_POWER_LEVEL_SET); + } + break; +#endif + + case gInitializationComplete_c: + /* Common GAP configuration */ + BleConnManager_GapCommonConfig(); + + /* Set the local synchronization event */ + xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_INIT_COMPLETE); + break; + default: + break; + } +} + +void BLEManagerCommon::blekw_gap_advertising_cb(gapAdvertisingEvent_t * pAdvertisingEvent) +{ + if (pAdvertisingEvent->eventType == gAdvertisingStateChanged_c) + { + /* Set the local synchronization event */ + xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_CHANGED); + } + else + { + /* The advertisement start failed */ + ChipLogProgress(DeviceLayer, "Advertising failed: event=%d reason=0x%04X\n", pAdvertisingEvent->eventType, + pAdvertisingEvent->eventData.failReason); + + /* Set the local synchronization event */ + xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_ADV_FAILED); + } +} + +void BLEManagerCommon::blekw_gap_connection_cb(deviceId_t deviceId, gapConnectionEvent_t * pConnectionEvent) +{ + /* Call BLE Conn Manager */ + BleConnManager_GapPeripheralEvent(deviceId, pConnectionEvent); + + if (pConnectionEvent->eventType == gConnEvtConnected_c) + { +#if CHIP_DEVICE_K32W1 +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + /* Disallow must be called here for K32W1, otherwise an assert will be reached. + * Disclaimer: this is a workaround until a better cross platform solution is found. */ + PWR_DisallowDeviceToSleep(); +#endif +#endif + +#if CHIP_DEVICE_CONFIG_BLE_SET_PHY_2M_REQ + ChipLogProgress(DeviceLayer, "BLE K32W: Trying to set the PHY to 2M"); + + (void) Gap_LeSetPhy(FALSE, deviceId, 0, gConnPhyUpdateReqTxPhySettings_c, gConnPhyUpdateReqRxPhySettings_c, + (uint16_t) gConnPhyUpdateReqPhyOptions_c); +#endif + + /* Notify App Task that the BLE is connected now */ + (void) blekw_msg_add_u8(BLE_KW_MSG_CONNECTED, (uint8_t) deviceId); +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + PWR_AllowDeviceToSleep(); +#endif + } + else if (pConnectionEvent->eventType == gConnEvtDisconnected_c) + { + blekw_stop_connection_timeout(); + + /* Notify App Task that the BLE is disconnected now */ + (void) blekw_msg_add_u8(BLE_KW_MSG_DISCONNECTED, (uint8_t) deviceId); + +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + if (bleAppStopInProgress == TRUE) + { + bleAppStopInProgress = FALSE; + PWR_AllowDeviceToSleep(); + } +#endif + } + else if (pConnectionEvent->eventType == gConnEvtPairingRequest_c) + { + /* Reject request for pairing */ + Gap_RejectPairing(deviceId, gPairingNotSupported_c); + } + else if (pConnectionEvent->eventType == gConnEvtAuthenticationRejected_c) + { + ChipLogProgress(DeviceLayer, "BLE Authentication rejected (reason:%d).\n", + pConnectionEvent->eventData.authenticationRejectedEvent.rejectReason); + } +} + +void BLEManagerCommon::blekw_connection_timeout_cb(TimerHandle_t timer) +{ + (void) blekw_msg_add_u8(BLE_KW_MSG_FORCE_DISCONNECT, 0); +} + +void BLEManagerCommon::blekw_start_connection_timeout(void) +{ + xTimerReset(connectionTimeout, 0); +} + +void BLEManagerCommon::blekw_stop_connection_timeout(void) +{ + ChipLogProgress(DeviceLayer, "Stopped connectionTimeout timer."); + xTimerStop(connectionTimeout, 0); +} + +void BLEManagerCommon::blekw_gatt_server_cb(deviceId_t deviceId, gattServerEvent_t * pServerEvent) +{ + if (sImplInstance && sImplInstance->callbackDelegate.gattCallback) + { + sImplInstance->callbackDelegate.gattCallback(deviceId, pServerEvent); + } + + switch (pServerEvent->eventType) + { + case gEvtMtuChanged_c: { + uint16_t tempMtu = 0; + + (void) Gatt_GetMtu(deviceId, &tempMtu); + blekw_msg_add_u16(BLE_KW_MSG_MTU_CHANGED, tempMtu); + break; + } + + case gEvtAttributeWritten_c: + blekw_msg_add_att_written(BLE_KW_MSG_ATT_WRITTEN, deviceId, pServerEvent->eventData.attributeWrittenEvent.handle, + pServerEvent->eventData.attributeWrittenEvent.aValue, + pServerEvent->eventData.attributeWrittenEvent.cValueLength); + break; + + case gEvtLongCharacteristicWritten_c: + blekw_msg_add_att_written(BLE_KW_MSG_ATT_LONG_WRITTEN, deviceId, pServerEvent->eventData.longCharWrittenEvent.handle, + pServerEvent->eventData.longCharWrittenEvent.aValue, + pServerEvent->eventData.longCharWrittenEvent.cValueLength); + break; + + case gEvtAttributeRead_c: + blekw_msg_add_att_read(BLE_KW_MSG_ATT_READ, deviceId, pServerEvent->eventData.attributeReadEvent.handle); + break; + + case gEvtCharacteristicCccdWritten_c: { + uint16_t cccd_val = pServerEvent->eventData.charCccdWrittenEvent.newCccd; + + blekw_msg_add_att_written(BLE_KW_MSG_ATT_CCCD_WRITTEN, deviceId, pServerEvent->eventData.charCccdWrittenEvent.handle, + (uint8_t *) &cccd_val, 2); + break; + } + + case gEvtHandleValueConfirmation_c: + /* Set the local synchronization event */ + xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_INDICATION_CONFIRMED); + break; + + case gEvtError_c: + if (pServerEvent->eventData.procedureError.procedureType == gSendIndication_c) + { + /* Set the local synchronization event */ + xEventGroupSetBits(sEventGroup, CHIP_BLE_KW_EVNT_INDICATION_FAILED); + } + else + { + ChipLogProgress(DeviceLayer, "BLE Gatt Server Error: Code 0x%04X, Source %d.\n", + pServerEvent->eventData.procedureError.error, pServerEvent->eventData.procedureError.procedureType); + + /* Notify CHIP BLE App Task that the BLE hardware report fail */ + (void) blekw_msg_add_u8(BLE_KW_MSG_ERROR, BLE_INTERNAL_GATT_ERROR); + } + break; + + default: + break; + } +} +/******************************************************************************* + * Add to message queue functions + *******************************************************************************/ +CHIP_ERROR BLEManagerCommon::blekw_msg_add_att_written(blekw_msg_type_t type, uint8_t device_id, uint16_t handle, uint8_t * data, + uint16_t length) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + blekw_msg_t * msg = NULL; + blekw_att_written_data_t * att_wr_data; + + /* Allocate a buffer with enough space to store the packet */ + msg = (blekw_msg_t *) malloc(sizeof(blekw_msg_t) + sizeof(blekw_att_written_data_t) + length); + VerifyOrExit(msg, err = CHIP_ERROR_NO_MEMORY); + + msg->type = type; + msg->length = sizeof(blekw_att_written_data_t) + length; + att_wr_data = (blekw_att_written_data_t *) msg->data.data; + att_wr_data->device_id = device_id; + att_wr_data->handle = handle; + att_wr_data->length = length; + FLib_MemCpy(att_wr_data->data, data, length); + + VerifyOrExit(xQueueSend(sBleEventQueue, &msg, 0) == pdTRUE, err = CHIP_ERROR_NO_MEMORY); + otTaskletsSignalPending(NULL); + +exit: + return err; +} + +CHIP_ERROR BLEManagerCommon::blekw_msg_add_att_read(blekw_msg_type_t type, uint8_t device_id, uint16_t handle) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + blekw_msg_t * msg = NULL; + blekw_att_read_data_t * att_rd_data; + + /* Allocate a buffer with enough space to store the packet */ + msg = (blekw_msg_t *) malloc(sizeof(blekw_msg_t) + sizeof(blekw_att_read_data_t)); + VerifyOrExit(msg, err = CHIP_ERROR_NO_MEMORY); + + msg->type = type; + msg->length = sizeof(blekw_att_read_data_t); + att_rd_data = (blekw_att_read_data_t *) msg->data.data; + att_rd_data->device_id = device_id; + att_rd_data->handle = handle; + + VerifyOrExit(xQueueSend(sBleEventQueue, &msg, 0) == pdTRUE, err = CHIP_ERROR_NO_MEMORY); + otTaskletsSignalPending(NULL); + +exit: + return err; +} + +CHIP_ERROR BLEManagerCommon::blekw_msg_add_u8(blekw_msg_type_t type, uint8_t data) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + blekw_msg_t * msg = NULL; + + /* Allocate a buffer with enough space to store the packet */ + msg = (blekw_msg_t *) malloc(sizeof(blekw_msg_t)); + VerifyOrExit(msg, err = CHIP_ERROR_NO_MEMORY); + + msg->type = type; + msg->length = 0; + msg->data.u8 = data; + + VerifyOrExit(xQueueSend(sBleEventQueue, &msg, 0) == pdTRUE, err = CHIP_ERROR_NO_MEMORY); + otTaskletsSignalPending(NULL); + +exit: + return err; +} + +CHIP_ERROR BLEManagerCommon::blekw_msg_add_u16(blekw_msg_type_t type, uint16_t data) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + blekw_msg_t * msg = NULL; + + /* Allocate a buffer with enough space to store the packet */ + msg = (blekw_msg_t *) malloc(sizeof(blekw_msg_t)); + VerifyOrExit(msg, err = CHIP_ERROR_NO_MEMORY); + + msg->type = type; + msg->length = 0; + msg->data.u16 = data; + + VerifyOrExit(xQueueSend(sBleEventQueue, &msg, 0) == pdTRUE, err = CHIP_ERROR_NO_MEMORY); + otTaskletsSignalPending(NULL); + +exit: + return err; +} + +void BLEManagerCommon::BleAdvTimeoutHandler(TimerHandle_t xTimer) +{ + if (BLEMgrImpl().mFlags.Has(Flags::kFastAdvertisingEnabled)) + { + ChipLogDetail(DeviceLayer, "Start slow advertisement"); + BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising); + } +} + +void BLEManagerCommon::CancelBleAdvTimeoutTimer(void) +{ + if (xTimerStop(sbleAdvTimeoutTimer, 0) == pdFAIL) + { + ChipLogError(DeviceLayer, "Failed to stop BledAdv timeout timer"); + } +} + +void BLEManagerCommon::StartBleAdvTimeoutTimer(uint32_t aTimeoutInMs) +{ + if (xTimerIsTimerActive(sbleAdvTimeoutTimer)) + { + CancelBleAdvTimeoutTimer(); + } + + // timer is not active, change its period to required value (== restart). + // FreeRTOS- Block for a maximum of 100 ticks if the change period command + // cannot immediately be sent to the timer command queue. + if (xTimerChangePeriod(sbleAdvTimeoutTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) + { + ChipLogError(DeviceLayer, "Failed to start BledAdv timeout timer"); + } +} + +CHIP_ERROR BLEManagerCommon::blekw_stop_connection_internal(BLE_CONNECTION_OBJECT conId) +{ + ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %u)", conId); + + if (Gap_Disconnect(conId) != gBleSuccess_c) + { + ChipLogProgress(DeviceLayer, "Gap_Disconnect() failed."); + return CHIP_ERROR_INTERNAL; + } +#if defined(chip_with_low_power) && (chip_with_low_power == 1) + else + { + bleAppStopInProgress = TRUE; + PWR_DisallowDeviceToSleep(); + } +#endif + + return CHIP_NO_ERROR; +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip +#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/src/platform/nxp/common/legacy/BLEManagerCommon.h b/src/platform/nxp/common/legacy/BLEManagerCommon.h new file mode 100644 index 00000000000000..b7fc1275d2501f --- /dev/null +++ b/src/platform/nxp/common/legacy/BLEManagerCommon.h @@ -0,0 +1,249 @@ +/* + * + * Copyright (c) 2020-2021 Project CHIP Authors + * Copyright (c) 2020 Nest Labs, Inc. + * All rights reserved. + * + * 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. + */ + +/** + * @file + * Provides an implementation of the BLEManager singleton object + * for the K32W platforms. + */ + +#pragma once + +#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE + +#include "fsl_os_abstraction.h" + +#include "ble_conn_manager.h" +#include "ble_general.h" +#include "ble_host_task_config.h" +#include "ble_host_tasks.h" +#include "gap_interface.h" +#include "gatt_db_dynamic.h" +#include "gatt_server_interface.h" + +#include "FreeRTOS.h" +#include "event_groups.h" +#include "timers.h" + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +using namespace chip::Ble; + +/** + * A delegate class that can be used by the application to subscribe to BLE events. + */ +struct BLECallbackDelegate +{ + using GapGenericCallback = void (*)(gapGenericEvent_t * event); + using GattServerCallback = void (*)(deviceId_t id, gattServerEvent_t * event); + + GapGenericCallback gapCallback = nullptr; + GattServerCallback gattCallback = nullptr; +}; + +/** + * Base class for different platform implementations (K32W0 and K32W1 for now). + */ +class BLEManagerCommon : public BLEManager, protected BleLayer, private BlePlatformDelegate, private BleApplicationDelegate +{ +protected: + // ===== Members that implement the BLEManager internal interface. + + CHIP_ERROR _Init(void); + CHIP_ERROR _Shutdown() { return CHIP_NO_ERROR; } + CHIPoBLEServiceMode _GetCHIPoBLEServiceMode(void); + CHIP_ERROR _SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val); + bool _IsAdvertisingEnabled(void); + CHIP_ERROR _SetAdvertisingEnabled(bool val); + bool _IsAdvertising(void); + CHIP_ERROR _SetAdvertisingMode(BLEAdvertisingMode mode); + CHIP_ERROR _GetDeviceName(char * buf, size_t bufSize); + CHIP_ERROR _SetDeviceName(const char * deviceName); + uint16_t _NumConnections(void); + void _OnPlatformEvent(const ChipDeviceEvent * event); + + // ===== Members that implement virtual methods on BlePlatformDelegate. + + CHIP_ERROR SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, + const Ble::ChipBleUUID * charId) override; + CHIP_ERROR UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, + const Ble::ChipBleUUID * charId) override; + CHIP_ERROR CloseConnection(BLE_CONNECTION_OBJECT conId) override; + uint16_t GetMTU(BLE_CONNECTION_OBJECT conId) const override; + CHIP_ERROR SendIndication(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId, + System::PacketBufferHandle pBuf) override; + CHIP_ERROR SendWriteRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId, + System::PacketBufferHandle pBuf) override; + + // ===== Members that implement virtual methods on BleApplicationDelegate. + + void NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) override; + + // ===== Private members reserved for use by this class only. + + enum class Flags : uint8_t + { + kAdvertisingEnabled = 0x0001, + kFastAdvertisingEnabled = 0x0002, + kAdvertising = 0x0004, + kRestartAdvertising = 0x0008, + kK32WBLEStackInitialized = 0x0010, + kDeviceNameSet = 0x0020, + }; + BitFlags mFlags; + + enum + { + kMaxDeviceNameLength = 16, + kUnusedIndex = 0xFF, + }; + + typedef enum + { + BLE_KW_MSG_ERROR = 0x01, + BLE_KW_MSG_CONNECTED, + BLE_KW_MSG_DISCONNECTED, + BLE_KW_MSG_MTU_CHANGED, + BLE_KW_MSG_ATT_WRITTEN, + BLE_KW_MSG_ATT_LONG_WRITTEN, + BLE_KW_MSG_ATT_READ, + BLE_KW_MSG_ATT_CCCD_WRITTEN, + BLE_KW_MSG_FORCE_DISCONNECT, + } blekw_msg_type_t; + + typedef struct hk_ble_kw_msg_s + { + blekw_msg_type_t type; + uint16_t length; + union + { + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint8_t data[1]; + char * str; + } data; + } blekw_msg_t; + + typedef enum ble_err_t + { + BLE_OK = 0, + BLE_INTERNAL_GATT_ERROR, + BLE_E_SET_ADV_PARAMS, + BLE_E_ADV_PARAMS_FAILED, + BLE_E_SET_ADV_DATA, + BLE_E_ADV_CHANGED, + BLE_E_ADV_FAILED, + BLE_E_ADV_SETUP_FAILED, + BLE_E_START_ADV, + BLE_E_STOP, + BLE_E_FAIL, + BLE_E_START_ADV_FAILED, + BLE_KW_MSG_2M_UPGRADE_ERROR, + BLE_INTERNAL_ERROR, + } ble_err_t; + + typedef struct ble_att_written_data_s + { + uint8_t device_id; + uint16_t handle; + uint16_t length; + uint8_t data[1]; + } blekw_att_written_data_t; + + typedef struct hk_ble_att_read_data_s + { + uint8_t device_id; + uint16_t handle; + } blekw_att_read_data_t; + + CHIPoBLEServiceMode mServiceMode; + char mDeviceName[kMaxDeviceNameLength + 1]; +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + chip::System::PacketBufferHandle c3AdditionalDataBufferHandle; +#endif + uint8_t mDeviceId; + bool mDeviceSubscribed = false; + bool mDeviceConnected = false; + + void DriveBLEState(void); + CHIP_ERROR ConfigureAdvertising(void); + CHIP_ERROR ConfigureAdvertisingData(void); + CHIP_ERROR StartAdvertising(void); + CHIP_ERROR StopAdvertising(void); + + void HandleConnectEvent(blekw_msg_t * msg); + void HandleConnectionCloseEvent(blekw_msg_t * msg); + void HandleWriteEvent(blekw_msg_t * msg); + void HandleRXCharWrite(blekw_msg_t * msg); + void HandleTXCharCCCDWrite(blekw_msg_t * msg); + void HandleForceDisconnect(); + +#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING + CHIP_ERROR EncodeAdditionalDataTlv(); + void HandleC3ReadRequest(blekw_msg_t * msg); +#endif + BLEManagerCommon::ble_err_t blekw_send_event(int8_t connection_handle, uint16_t handle, uint8_t * data, uint32_t len); + + static void DriveBLEState(intptr_t arg); + static void StopAdvertisingPriorToSwitchingMode(intptr_t arg); + static void BleAdvTimeoutHandler(TimerHandle_t xTimer); + static void CancelBleAdvTimeoutTimer(void); + static void StartBleAdvTimeoutTimer(uint32_t aTimeoutInMs); + + static void blekw_connection_timeout_cb(TimerHandle_t timer); + static void blekw_generic_cb(gapGenericEvent_t * pGenericEvent); + static void blekw_gatt_server_cb(deviceId_t deviceId, gattServerEvent_t * pServerEvent); + static CHIP_ERROR blekw_msg_add_u8(blekw_msg_type_t type, uint8_t data); + static CHIP_ERROR blekw_msg_add_u16(blekw_msg_type_t type, uint16_t data); + static CHIP_ERROR blekw_msg_add_att_written(blekw_msg_type_t type, uint8_t device_id, uint16_t handle, uint8_t * data, + uint16_t length); + static CHIP_ERROR blekw_msg_add_att_read(blekw_msg_type_t type, uint8_t device_id, uint16_t handle); + static BLEManagerCommon::ble_err_t blekw_start_advertising(gapAdvertisingParameters_t * adv_params, gapAdvertisingData_t * adv, + gapScanResponseData_t * scnrsp); + static BLEManagerCommon::ble_err_t blekw_stop_advertising(void); + static void blekw_gap_advertising_cb(gapAdvertisingEvent_t * pAdvertisingEvent); + static void blekw_gap_connection_cb(deviceId_t deviceId, gapConnectionEvent_t * pConnectionEvent); + static void blekw_start_connection_timeout(void); + static void blekw_stop_connection_timeout(void); + static CHIP_ERROR blekw_stop_connection_internal(BLE_CONNECTION_OBJECT conId); + +public: + virtual CHIP_ERROR InitHostController(BLECallbackDelegate::GapGenericCallback cb_fp) = 0; + virtual BLEManagerCommon * GetImplInstance() = 0; + virtual CHIP_ERROR ResetController() { return CHIP_NO_ERROR; } + void DoBleProcessing(void); + + BLECallbackDelegate callbackDelegate; + void RegisterAppCallbacks(BLECallbackDelegate::GapGenericCallback gapCallback, + BLECallbackDelegate::GattServerCallback gattCallback); +}; + +inline BLEManager::CHIPoBLEServiceMode BLEManagerCommon::_GetCHIPoBLEServiceMode(void) +{ + return mServiceMode; +} + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE diff --git a/src/platform/nxp/common/legacy/FactoryDataDriver.cpp b/src/platform/nxp/common/legacy/FactoryDataDriver.cpp new file mode 100644 index 00000000000000..6ddbedc3ca35c8 --- /dev/null +++ b/src/platform/nxp/common/legacy/FactoryDataDriver.cpp @@ -0,0 +1,76 @@ +/* + * + * Copyright (c) 2024 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. + */ + +#include +#include +#include +#include + +namespace chip { +namespace DeviceLayer { + +FactoryDataDriver::~FactoryDataDriver() {} + +CHIP_ERROR FactoryDataDriver::UpdateValueInRam(uint8_t tag, ByteSpan & newValue) +{ + uint16_t oldLength = 0; + uint16_t newLength = newValue.size(); + uint32_t offset = 0; + uint8_t * factoryData = mFactoryDataRamBuff; + FactoryDataProvider::Header * header = (FactoryDataProvider::Header *) factoryData; + uint8_t * data = factoryData + sizeof(FactoryDataProvider::Header); + + while (offset < header->size) + { + memcpy(&oldLength, &data[offset + FactoryDataProvider::kLengthOffset], sizeof(oldLength)); + + if (tag != data[offset]) + { + offset += FactoryDataProvider::kValueOffset + oldLength; + continue; + } + + if (oldLength == newLength) + { + memcpy(&data[offset + FactoryDataProvider::kValueOffset], newValue.data(), newLength); + } + else + { + uint32_t oldEndOffset = offset + FactoryDataProvider::kValueOffset + oldLength; + + memcpy(&data[offset + FactoryDataProvider::kLengthOffset], &newLength, sizeof(newLength)); + memmove(&data[offset + FactoryDataProvider::kValueOffset + newLength], &data[oldEndOffset], + header->size - oldEndOffset); + memcpy(&data[offset + FactoryDataProvider::kValueOffset], newValue.data(), newLength); + } + + header->size = header->size - oldLength + newLength; + + uint8_t sha256Output[SHA256_HASH_SIZE] = { 0 }; + SHA256_Hash(data, header->size, sha256Output); + memcpy(header->hash, sha256Output, sizeof(header->hash)); + + ChipLogProgress(DeviceLayer, "Value at tag %d updated successfully.", tag); + return CHIP_NO_ERROR; + } + + ChipLogError(DeviceLayer, "Failed to find tag %d.", tag); + return CHIP_ERROR_NOT_FOUND; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/common/legacy/FactoryDataDriver.h b/src/platform/nxp/common/legacy/FactoryDataDriver.h new file mode 100644 index 00000000000000..93eb43a183e23c --- /dev/null +++ b/src/platform/nxp/common/legacy/FactoryDataDriver.h @@ -0,0 +1,113 @@ +/* + * + * Copyright (c) 2024 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. + */ +#pragma once + +namespace chip { +namespace DeviceLayer { + +// Forward declaration to define the getter for factory data provider impl instance +class FactoryDataDriverImpl; + +/** + * @brief This interface provides the functions that should be implemented + * to handle factory data update and factory data ram backup operations. + * This interface must be implemented by each platform. + */ + +class FactoryDataDriver +{ +public: + virtual ~FactoryDataDriver(); + + /*! + * \brief Initializes the FactoryDataDriver instance. + * + * @retval CHIP_NO_ERROR if operation was successful. + */ + virtual CHIP_ERROR Init() = 0; + + /*! + * \brief Checks whether the backup of the factory data exists (e.g in persistent storage). + * + * @retval true if backup exists otherwise return false. + */ + virtual bool DoesBackupExist(uint16_t * size) = 0; + + /*! + * \brief Deletes the backup of the factory data (e.g. from persistent storage). + * + * @retval CHIP_NO_ERROR if operation was successful. + */ + virtual CHIP_ERROR DeleteBackup(void) = 0; + + /*! + * \brief Allocates and initializes the factory data ram backup and copies + * factory data into it. + * + * @retval CHIP_NO_ERROR if operation was successful. + */ + virtual CHIP_ERROR InitRamBackup(void) = 0; + + /*! + * \brief Clear and deallocate the factory data ram backup. + * + * @retval CHIP_NO_ERROR if operation was successful. + */ + virtual CHIP_ERROR ClearRamBackup(void) = 0; + + /*! + * \brief Read the factory data from persistent storage into the factory data + * ram backup. + * + * @retval CHIP_NO_ERROR if operation was successful. + */ + virtual CHIP_ERROR ReadBackupInRam(void) = 0; + + /*! + * \brief Save / Backup the factory data into the persistent storage + * + * @retval CHIP_NO_ERROR if operation was successful. + */ + virtual CHIP_ERROR BackupFactoryData(void) = 0; + + /*! + * \brief Update / Write the factory data from the ram buffer + * + * @retval CHIP_NO_ERROR if operation was successful. + */ + virtual CHIP_ERROR UpdateFactoryData(void) = 0; + + /*! + * \brief Update TLV value from factory data based on tag + * @param tag TLV tag of component to update + * @param newValue Reference to the new value of the TLV component + * @retval CHIP_NO_ERROR if operation was successful. + */ + CHIP_ERROR UpdateValueInRam(uint8_t tag, ByteSpan & newValue); + +protected: + uint8_t * mFactoryDataRamBuff = nullptr; + uint32_t mSize = 0; + uint32_t mMaxSize = 0; +}; + +extern FactoryDataDriver & FactoryDataDrv(); + +extern FactoryDataDriverImpl & FactoryDataDrvImpl(); + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/common/legacy/FactoryDataProvider.cpp b/src/platform/nxp/common/legacy/FactoryDataProvider.cpp new file mode 100644 index 00000000000000..7ecc29a54cf077 --- /dev/null +++ b/src/platform/nxp/common/legacy/FactoryDataProvider.cpp @@ -0,0 +1,442 @@ +/* + * + * Copyright (c) 2022 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. + */ + +#if (!CONFIG_CHIP_LOAD_REAL_FACTORY_DATA || !(defined CONFIG_CHIP_LOAD_REAL_FACTORY_DATA)) +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace chip { +namespace DeviceLayer { + +static constexpr size_t kSpake2pSerializedVerifier_MaxBase64Len = + BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_VerifierSerialized_Length) + 1; +static constexpr size_t kSpake2pSalt_MaxBase64Len = BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length) + 1; +/* Secure subsystem private key blob size is 32 + 24 = 56. + * DAC private key may be used to store an SSS exported blob instead of the private key. + */ +static constexpr size_t kDacPrivateKey_MaxLen = Crypto::kP256_PrivateKey_Length + 24; + +FactoryDataProvider::~FactoryDataProvider() {} + +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR + +CHIP_ERROR FactoryDataProvider::ValidateWithRestore() +{ + CHIP_ERROR error = CHIP_NO_ERROR; + + VerifyOrReturnError(mRestoreMechanisms.size() > 0, CHIP_FACTORY_DATA_RESTORE_MECHANISM); + + for (auto & restore : mRestoreMechanisms) + { + error = restore(); + if (error != CHIP_NO_ERROR) + { + continue; + } + + error = Validate(); + if (error != CHIP_NO_ERROR) + { + continue; + } + + break; + } + + if (error == CHIP_NO_ERROR) + { + error = mFactoryDataDriver->DeleteBackup(); + } + + return error; +} + +void FactoryDataProvider::RegisterRestoreMechanism(RestoreMechanism restore) +{ + mRestoreMechanisms.insert(mRestoreMechanisms.end(), restore); +} + +#endif + +CHIP_ERROR FactoryDataProvider::SignWithDacKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + Crypto::P256ECDSASignature signature; + Crypto::P256Keypair keypair; + Crypto::P256SerializedKeypair serializedKeypair; + uint8_t keyBuf[Crypto::kP256_PrivateKey_Length]; + MutableByteSpan dacPrivateKeySpan(keyBuf); + uint16_t keySize = 0; + + VerifyOrExit(!outSignBuffer.empty(), error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(!messageToSign.empty(), error = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(outSignBuffer.size() >= signature.Capacity(), error = CHIP_ERROR_BUFFER_TOO_SMALL); + + /* Get private key of DAC certificate from reserved section */ + error = SearchForId(FactoryDataId::kDacPrivateKeyId, dacPrivateKeySpan.data(), dacPrivateKeySpan.size(), keySize); + SuccessOrExit(error); + dacPrivateKeySpan.reduce_size(keySize); + + /* Only the private key is used when signing */ + error = serializedKeypair.SetLength(Crypto::kP256_PublicKey_Length + dacPrivateKeySpan.size()); + SuccessOrExit(error); + memcpy(serializedKeypair.Bytes() + Crypto::kP256_PublicKey_Length, dacPrivateKeySpan.data(), dacPrivateKeySpan.size()); + + error = keypair.Deserialize(serializedKeypair); + SuccessOrExit(error); + + error = keypair.ECDSA_sign_msg(messageToSign.data(), messageToSign.size(), signature); + SuccessOrExit(error); + + error = CopySpanToMutableSpan(ByteSpan{ signature.ConstBytes(), signature.Length() }, outSignBuffer); + +exit: + /* Sanitize temporary buffer */ + memset(keyBuf, 0, Crypto::kP256_PrivateKey_Length); + return error; +} + +CHIP_ERROR FactoryDataProvider::Validate() +{ + uint8_t output[Crypto::kSHA256_Hash_Length] = { 0 }; + + memcpy(&mHeader, (void *) mConfig.start, sizeof(Header)); + ReturnErrorCodeIf(mHeader.hashId != kHashId, CHIP_FACTORY_DATA_HASH_ID); + + ReturnErrorOnFailure(Crypto::Hash_SHA256((uint8_t *) mConfig.payload, mHeader.size, output)); + ReturnErrorCodeIf(memcmp(output, mHeader.hash, kHashLen) != 0, CHIP_FACTORY_DATA_SHA_CHECK); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, + uint32_t * offset) +{ + uint32_t addr = mConfig.payload; + uint8_t type = 0; + + while (addr < (mConfig.payload + mHeader.size)) + { + memcpy(&type, (void *) addr, sizeof(type)); + memcpy(&length, (void *) (addr + 1), sizeof(length)); + + if (searchedType == type) + { + ReturnErrorCodeIf(bufLength < length, CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(pBuf, (void *) (addr + kValueOffset), length); + + if (offset) + *offset = (addr - mConfig.payload); + + return CHIP_NO_ERROR; + } + else + { + /* Jump past 3 bytes of length and then use length to jump to next data */ + addr = addr + kValueOffset + length; + } + } + + return CHIP_ERROR_NOT_FOUND; +} + +CHIP_ERROR FactoryDataProvider::GetCertificationDeclaration(MutableByteSpan & outBuffer) +{ +#if CHIP_USE_DEVICE_CONFIG_CERTIFICATION_DECLARATION + constexpr uint8_t kCdForAllExamples[] = CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION; + + return CopySpanToMutableSpan(ByteSpan{ kCdForAllExamples }, outBuffer); +#else + uint16_t declarationSize = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kCertDeclarationId, outBuffer.data(), outBuffer.size(), declarationSize)); + outBuffer.reduce_size(declarationSize); + + return CHIP_NO_ERROR; +#endif +} + +CHIP_ERROR FactoryDataProvider::GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetDeviceAttestationCert(MutableByteSpan & outBuffer) +{ + uint16_t certificateSize = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacCertificateId, outBuffer.data(), outBuffer.size(), certificateSize)); + outBuffer.reduce_size(certificateSize); + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductAttestationIntermediateCert(MutableByteSpan & outBuffer) +{ + uint16_t certificateSize = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kPaiCertificateId, outBuffer.data(), outBuffer.size(), certificateSize)); + outBuffer.reduce_size(certificateSize); + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::SignWithDeviceAttestationKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer) +{ + return SignWithDacKey(messageToSign, outSignBuffer); +} + +CHIP_ERROR FactoryDataProvider::GetSetupDiscriminator(uint16_t & setupDiscriminator) +{ + uint32_t discriminator = 0; + uint16_t temp = 0; + + ReturnErrorOnFailure(SearchForId(FactoryDataId::kDiscriminatorId, (uint8_t *) &discriminator, sizeof(discriminator), temp)); + setupDiscriminator = (uint16_t) (discriminator & 0x0000FFFF); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::SetSetupDiscriminator(uint16_t setupDiscriminator) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR FactoryDataProvider::GetSpake2pIterationCount(uint32_t & iterationCount) +{ + uint16_t temp = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kIcId, (uint8_t *) &iterationCount, sizeof(iterationCount), temp)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetSpake2pSalt(MutableByteSpan & saltBuf) +{ + char saltB64[kSpake2pSalt_MaxBase64Len] = { 0 }; + uint16_t saltB64Len = 0; + + ReturnErrorOnFailure(SearchForId(FactoryDataId::kSaltId, (uint8_t *) (&saltB64[0]), sizeof(saltB64), saltB64Len)); + size_t saltLen = chip::Base64Decode32(saltB64, saltB64Len, reinterpret_cast(saltB64)); + + ReturnErrorCodeIf(saltLen > saltBuf.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(saltBuf.data(), saltB64, saltLen); + saltBuf.reduce_size(saltLen); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetSpake2pVerifier(MutableByteSpan & verifierBuf, size_t & verifierLen) +{ + char verifierB64[kSpake2pSerializedVerifier_MaxBase64Len] = { 0 }; + uint16_t verifierB64Len = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kVerifierId, (uint8_t *) &verifierB64[0], sizeof(verifierB64), verifierB64Len)); + + verifierLen = chip::Base64Decode32(verifierB64, verifierB64Len, reinterpret_cast(verifierB64)); + ReturnErrorCodeIf(verifierLen > verifierBuf.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(verifierBuf.data(), verifierB64, verifierLen); + verifierBuf.reduce_size(verifierLen); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetSetupPasscode(uint32_t & setupPasscode) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kSetupPasscodeId, (uint8_t *) &setupPasscode, sizeof(setupPasscode), length)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::SetSetupPasscode(uint32_t setupPasscode) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR FactoryDataProvider::GetVendorName(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kVendorNameId, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetVendorId(uint16_t & vendorId) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kVidId, (uint8_t *) &vendorId, sizeof(vendorId), length)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductName(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kProductNameId, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductId(uint16_t & productId) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kPidId, (uint8_t *) &productId, sizeof(productId), length)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetPartNumber(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kPartNumber, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductURL(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kProductURL, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductLabel(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kProductLabel, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetSerialNumber(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kSerialNumberId, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) +{ + uint16_t length = 0; + uint8_t date[ConfigurationManager::kMaxManufacturingDateLength]; + + ReturnErrorOnFailure( + SearchForId(FactoryDataId::kManufacturingDateId, date, ConfigurationManager::kMaxManufacturingDateLength, length)); + date[length] = '\0'; + + if (length == 10 && isdigit(date[0]) && isdigit(date[1]) && isdigit(date[2]) && isdigit(date[3]) && date[4] == '-' && + isdigit(date[5]) && isdigit(date[6]) && date[7] == '-' && isdigit(date[8]) && isdigit(date[9])) + { + year = 1000 * (date[0] - '0') + 100 * (date[1] - '0') + 10 * (date[2] - '0') + date[3] - '0'; + month = 10 * (date[5] - '0') + date[6] - '0'; + day = 10 * (date[8] - '0') + date[9] - '0'; + } + else + { + ChipLogError(DeviceLayer, "Manufacturing date is not formatted correctly: YYYY-MM-DD."); + return CHIP_ERROR_INVALID_ARGUMENT; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetHardwareVersion(uint16_t & hardwareVersion) +{ + uint16_t length = 0; + ReturnErrorOnFailure( + SearchForId(FactoryDataId::kHardwareVersionId, (uint8_t *) &hardwareVersion, sizeof(hardwareVersion), length)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetHardwareVersionString(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kHardwareVersionStrId, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) +{ + CHIP_ERROR err = CHIP_ERROR_NOT_IMPLEMENTED; +#if CHIP_ENABLE_ROTATING_DEVICE_ID + static_assert(ConfigurationManager::kRotatingDeviceIDUniqueIDLength >= ConfigurationManager::kMinRotatingDeviceIDUniqueIDLength, + "Length of unique ID for rotating device ID is smaller than minimum."); + uint16_t uniqueIdLen = 0; + err = SearchForId(FactoryDataId::kUniqueId, (uint8_t *) uniqueIdSpan.data(), uniqueIdSpan.size(), uniqueIdLen); +#if defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) + if (err != CHIP_NO_ERROR) + { + constexpr uint8_t uniqueId[] = CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID; + + ReturnErrorCodeIf(sizeof(uniqueId) > uniqueIdSpan.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(uniqueIdSpan.data(), uniqueId, sizeof(uniqueId)); + uniqueIdLen = sizeof(uniqueId); + err = CHIP_NO_ERROR; + } +#endif // CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID + ReturnErrorOnFailure(err); + uniqueIdSpan.reduce_size(uniqueIdLen); +#endif + + return err; +} + +CHIP_ERROR FactoryDataProvider::GetProductFinish(app::Clusters::BasicInformation::ProductFinishEnum * finish) +{ + uint8_t productFinish; + uint16_t length = 0; + auto err = SearchForId(FactoryDataId::kProductFinish, &productFinish, sizeof(productFinish), length); + ReturnErrorCodeIf(err != CHIP_NO_ERROR, CHIP_ERROR_NOT_IMPLEMENTED); + + *finish = static_cast(productFinish); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductPrimaryColor(app::Clusters::BasicInformation::ColorEnum * primaryColor) +{ + uint8_t color; + uint16_t length = 0; + auto err = SearchForId(FactoryDataId::kProductPrimaryColor, &color, sizeof(color), length); + ReturnErrorCodeIf(err != CHIP_NO_ERROR, CHIP_ERROR_NOT_IMPLEMENTED); + + *primaryColor = static_cast(color); + + return CHIP_NO_ERROR; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/common/legacy/FactoryDataProvider.h b/src/platform/nxp/common/legacy/FactoryDataProvider.h new file mode 100644 index 00000000000000..f7d05c3f1da1f4 --- /dev/null +++ b/src/platform/nxp/common/legacy/FactoryDataProvider.h @@ -0,0 +1,177 @@ +/* + * + * Copyright (c) 2022 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. + */ +#pragma once + +#include +#include +#include +#include + +#include + +#include + +#include "CHIPPlatformConfig.h" + +#include + +namespace chip { +namespace DeviceLayer { + +#define CHIP_FACTORY_DATA_ERROR(e) \ + ChipError(ChipError::Range::kLastRange, ((uint8_t) ChipError::Range::kLastRange << 2) | e, __FILE__, __LINE__) + +#define CHIP_FACTORY_DATA_SHA_CHECK CHIP_FACTORY_DATA_ERROR(0x01) +#define CHIP_FACTORY_DATA_HEADER_READ CHIP_FACTORY_DATA_ERROR(0x02) +#define CHIP_FACTORY_DATA_HASH_ID CHIP_FACTORY_DATA_ERROR(0x03) +#define CHIP_FACTORY_DATA_PDM_RESTORE CHIP_FACTORY_DATA_ERROR(0x04) +#define CHIP_FACTORY_DATA_NULL CHIP_FACTORY_DATA_ERROR(0x05) +#define CHIP_FACTORY_DATA_FLASH_ERASE CHIP_FACTORY_DATA_ERROR(0x06) +#define CHIP_FACTORY_DATA_FLASH_PROGRAM CHIP_FACTORY_DATA_ERROR(0x07) +#define CHIP_FACTORY_DATA_INTERNAL_FLASH_READ CHIP_FACTORY_DATA_ERROR(0x08) +#define CHIP_FACTORY_DATA_PDM_SAVE_RECORD CHIP_FACTORY_DATA_ERROR(0x09) +#define CHIP_FACTORY_DATA_PDM_READ_RECORD CHIP_FACTORY_DATA_ERROR(0x0A) +#define CHIP_FACTORY_DATA_RESTORE_MECHANISM CHIP_FACTORY_DATA_ERROR(0x0B) + +// Forward declaration to define the getter for factory data provider impl instance +class FactoryDataProviderImpl; + +/** + * @brief This class provides Commissionable data, Device Attestation Credentials, + * and Device Instance Info. + */ + +class FactoryDataProvider : public DeviceInstanceInfoProvider, + public CommissionableDataProvider, + public Credentials::DeviceAttestationCredentialsProvider +{ +public: + struct Header + { + uint32_t hashId; + uint32_t size; + uint8_t hash[4]; + }; + + struct FactoryDataConfig + { + uint32_t start; + uint32_t size; + uint32_t payload; + }; + + // Default factory data IDs + enum FactoryDataId + { + kVerifierId = 1, + kSaltId, + kIcId, + kDacPrivateKeyId, + kDacCertificateId, + kPaiCertificateId, + kDiscriminatorId, + kSetupPasscodeId, + kVidId, + kPidId, + kCertDeclarationId, + kVendorNameId, + kProductNameId, + kSerialNumberId, + kManufacturingDateId, + kHardwareVersionId, + kHardwareVersionStrId, + kUniqueId, + kPartNumber, + kProductURL, + kProductLabel, + kProductFinish, + kProductPrimaryColor, + kMaxId + }; + + static uint32_t kFactoryDataMaxSize; + static constexpr uint32_t kLengthOffset = 1; + static constexpr uint32_t kValueOffset = 3; + static constexpr uint32_t kHashLen = 4; + static constexpr size_t kHashId = 0xCE47BA5E; + + virtual ~FactoryDataProvider(); + + virtual CHIP_ERROR Init() = 0; + virtual CHIP_ERROR SignWithDacKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer); + virtual CHIP_ERROR Validate(); + + virtual CHIP_ERROR SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, + uint32_t * offset = nullptr); + +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR + using RestoreMechanism = CHIP_ERROR (*)(void); + + CHIP_ERROR ValidateWithRestore(); + void RegisterRestoreMechanism(RestoreMechanism mechanism); + + virtual CHIP_ERROR PreResetCheck() = 0; + virtual CHIP_ERROR PostResetCheck() = 0; +#endif + + // ===== Members functions that implement the CommissionableDataProvider + CHIP_ERROR GetSetupDiscriminator(uint16_t & setupDiscriminator) override; + CHIP_ERROR SetSetupDiscriminator(uint16_t setupDiscriminator) override; + CHIP_ERROR GetSpake2pIterationCount(uint32_t & iterationCount) override; + CHIP_ERROR GetSpake2pSalt(MutableByteSpan & saltBuf) override; + CHIP_ERROR GetSpake2pVerifier(MutableByteSpan & verifierBuf, size_t & verifierLen) override; + CHIP_ERROR GetSetupPasscode(uint32_t & setupPasscode) override; + CHIP_ERROR SetSetupPasscode(uint32_t setupPasscode) override; + + // ===== Members functions that implement the DeviceAttestationCredentialsProvider + CHIP_ERROR GetCertificationDeclaration(MutableByteSpan & outBuffer) override; + CHIP_ERROR GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) override; + CHIP_ERROR GetDeviceAttestationCert(MutableByteSpan & outBuffer) override; + CHIP_ERROR GetProductAttestationIntermediateCert(MutableByteSpan & outBuffer) override; + CHIP_ERROR SignWithDeviceAttestationKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer) override; + + // ===== Members functions that implement the GenericDeviceInstanceInfoProvider + CHIP_ERROR GetVendorName(char * buf, size_t bufSize) override; + CHIP_ERROR GetVendorId(uint16_t & vendorId) override; + CHIP_ERROR GetProductName(char * buf, size_t bufSize) override; + CHIP_ERROR GetProductId(uint16_t & productId) override; + CHIP_ERROR GetPartNumber(char * buf, size_t bufSize) override; + CHIP_ERROR GetProductURL(char * buf, size_t bufSize) override; + CHIP_ERROR GetProductLabel(char * buf, size_t bufSize) override; + CHIP_ERROR GetHardwareVersionString(char * buf, size_t bufSize) override; + CHIP_ERROR GetSerialNumber(char * buf, size_t bufSize) override; + CHIP_ERROR GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) override; + CHIP_ERROR GetHardwareVersion(uint16_t & hardwareVersion) override; + CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) override; + CHIP_ERROR GetProductFinish(app::Clusters::BasicInformation::ProductFinishEnum * finish) override; + CHIP_ERROR GetProductPrimaryColor(app::Clusters::BasicInformation::ColorEnum * primaryColor) override; + +protected: + Header mHeader; + FactoryDataConfig mConfig; +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR + std::vector mRestoreMechanisms; + FactoryDataDriver * mFactoryDataDriver = nullptr; +#endif +}; + +extern FactoryDataProvider & FactoryDataPrvd(); + +extern FactoryDataProviderImpl & FactoryDataPrvdImpl(); + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/common/legacy/OTAFactoryDataProcessor.cpp b/src/platform/nxp/common/legacy/OTAFactoryDataProcessor.cpp new file mode 100644 index 00000000000000..4960ca2c4e0669 --- /dev/null +++ b/src/platform/nxp/common/legacy/OTAFactoryDataProcessor.cpp @@ -0,0 +1,165 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include + +namespace chip { + +CHIP_ERROR OTAFactoryDataProcessor::Init() +{ + mAccumulator.Init(mLength); + mFactoryDataDriver = &chip::DeviceLayer::FactoryDataDrv(); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAFactoryDataProcessor::Clear() +{ + OTATlvProcessor::ClearInternal(); + mAccumulator.Clear(); + mPayload.Clear(); + mFactoryDataDriver->ClearRamBackup(); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAFactoryDataProcessor::ProcessInternal(ByteSpan & block) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + + ReturnErrorOnFailure(mAccumulator.Accumulate(block)); +#if OTA_ENCRYPTION_ENABLE + MutableByteSpan mBlock = MutableByteSpan(mAccumulator.data(), mAccumulator.GetThreshold()); + OTATlvProcessor::vOtaProcessInternalEncryption(mBlock); +#endif + error = DecodeTlv(); + + if (error != CHIP_NO_ERROR) + { + // The factory data payload can contain a variable number of fields + // to be updated. CHIP_END_OF_TLV is returned if no more fields are + // found. + if (error == CHIP_END_OF_TLV) + { + return CHIP_NO_ERROR; + } + + Clear(); + } + + return error; +} + +CHIP_ERROR OTAFactoryDataProcessor::ApplyAction() +{ + CHIP_ERROR error = CHIP_NO_ERROR; + FactoryProvider * provider; + + ReturnErrorOnFailure(mFactoryDataDriver->InitRamBackup()); + ReturnErrorOnFailure(mFactoryDataDriver->BackupFactoryData()); + + SuccessOrExit(error = Update((uint8_t) Tags::kDacPrivateKeyId, mPayload.mCertDacKey)); + SuccessOrExit(error = Update((uint8_t) Tags::kDacCertificateId, mPayload.mCertDac)); + SuccessOrExit(error = Update((uint8_t) Tags::kPaiCertificateId, mPayload.mCertPai)); + SuccessOrExit(error = Update((uint8_t) Tags::kCertDeclarationId, mPayload.mCertDeclaration)); + + SuccessOrExit(error = mFactoryDataDriver->UpdateFactoryData()); + + provider = &chip::DeviceLayer::FactoryDataPrvd(); + VerifyOrReturnError(provider != nullptr, CHIP_ERROR_INTERNAL); + + SuccessOrExit(error = provider->PreResetCheck()); + +exit: + if (error != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Failed to update factory data. Error: %s", ErrorStr(error)); + } + else + { + ChipLogProgress(DeviceLayer, "Factory data update finished."); + } + + return error; +} + +CHIP_ERROR OTAFactoryDataProcessor::AbortAction() +{ + CHIP_ERROR error = CHIP_NO_ERROR; + ReturnErrorOnFailure(mFactoryDataDriver->ReadBackupInRam()); + ReturnErrorOnFailure(mFactoryDataDriver->UpdateFactoryData()); + + error = mFactoryDataDriver->DeleteBackup(); + ReturnErrorOnFailure(error); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAFactoryDataProcessor::DecodeTlv() +{ + TLV::TLVReader tlvReader; + tlvReader.Init(mAccumulator.data(), mLength); + ReturnErrorOnFailure(tlvReader.Next(TLV::TLVType::kTLVType_Structure, TLV::AnonymousTag())); + + TLV::TLVType outerType; + ReturnErrorOnFailure(tlvReader.EnterContainer(outerType)); + ReturnErrorOnFailure(tlvReader.Next()); + + if (tlvReader.GetTag() == TLV::ContextTag((uint8_t) Tags::kDacPrivateKeyId)) + { + ReturnErrorOnFailure(tlvReader.Get(mPayload.mCertDacKey.Emplace())); + ReturnErrorOnFailure(tlvReader.Next()); + } + + if (tlvReader.GetTag() == TLV::ContextTag((uint8_t) Tags::kDacCertificateId)) + { + ReturnErrorOnFailure(tlvReader.Get(mPayload.mCertDac.Emplace())); + ReturnErrorOnFailure(tlvReader.Next()); + } + + if (tlvReader.GetTag() == TLV::ContextTag((uint8_t) Tags::kPaiCertificateId)) + { + ReturnErrorOnFailure(tlvReader.Get(mPayload.mCertPai.Emplace())); + ReturnErrorOnFailure(tlvReader.Next()); + } + + if (tlvReader.GetTag() == TLV::ContextTag((uint8_t) Tags::kCertDeclarationId)) + { + ReturnErrorOnFailure(tlvReader.Get(mPayload.mCertDeclaration.Emplace())); + } + + ReturnErrorOnFailure(tlvReader.ExitContainer(outerType)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAFactoryDataProcessor::Update(uint8_t tag, Optional & optional) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + if (optional.HasValue()) + { + error = mFactoryDataDriver->UpdateValueInRam(tag, optional.Value()); + } + + return error; +} + +} // namespace chip diff --git a/src/platform/nxp/common/legacy/OTAFactoryDataProcessor.h b/src/platform/nxp/common/legacy/OTAFactoryDataProcessor.h new file mode 100644 index 00000000000000..862aad2d9a6341 --- /dev/null +++ b/src/platform/nxp/common/legacy/OTAFactoryDataProcessor.h @@ -0,0 +1,78 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include PLATFORM_FACTORY_DATA_PROVIDER_IMPL_HEADER + +namespace chip { + +using FactoryProvider = DeviceLayer::FactoryDataProvider; +using FactoryProviderImpl = DeviceLayer::FactoryDataProviderImpl; +using FactoryDataDriver = DeviceLayer::FactoryDataDriver; +using Tags = FactoryProvider::FactoryDataId; + +/** + * OTA custom payload that uses Matter TLVs. + * The custom payload is used when factory data needs updating. + * Factory data will be encoded using Matter TLV format to make + * use of the ChipTlv reader. A payload contains metadata (size of + * TLVs) and the TLVs themselves contained in a structure. + * If no factory data need to be updated, the metadata will be 0 + */ +struct OTAFactoryPayload +{ + Optional mCertDacKey; + Optional mCertDac; + Optional mCertPai; + Optional mCertDeclaration; + + void Clear() + { + mCertDacKey.ClearValue(); + mCertDac.ClearValue(); + mCertPai.ClearValue(); + mCertDeclaration.ClearValue(); + } +}; + +class OTAFactoryDataProcessor : public OTATlvProcessor +{ +public: + CHIP_ERROR Init() override; + CHIP_ERROR Clear() override; + CHIP_ERROR ApplyAction() override; + CHIP_ERROR AbortAction() override; + +private: + CHIP_ERROR ProcessInternal(ByteSpan & block) override; + CHIP_ERROR DecodeTlv(); + CHIP_ERROR Update(uint8_t tag, Optional & optional); + + OTAFactoryPayload mPayload; + OTADataAccumulator mAccumulator; + FactoryDataDriver * mFactoryDataDriver = nullptr; +}; + +} // namespace chip diff --git a/src/platform/nxp/common/legacy/OTAImageProcessorImpl.cpp b/src/platform/nxp/common/legacy/OTAImageProcessorImpl.cpp new file mode 100644 index 00000000000000..249b51b7681c22 --- /dev/null +++ b/src/platform/nxp/common/legacy/OTAImageProcessorImpl.cpp @@ -0,0 +1,424 @@ +/* + * + * Copyright (c) 2021-2023 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include + +using namespace chip::DeviceLayer; +using namespace ::chip::DeviceLayer::Internal; + +#if USE_SMU2_STATIC +// The attribute specifier should not be changed. +static chip::OTAImageProcessorImpl gImageProcessor __attribute__((section(".smu2"))); +#else +static chip::OTAImageProcessorImpl gImageProcessor; +#endif + +namespace chip { + +CHIP_ERROR OTAImageProcessorImpl::Init(OTADownloader * downloader) +{ + ReturnErrorCodeIf(downloader == nullptr, CHIP_ERROR_INVALID_ARGUMENT); + mDownloader = downloader; + + OtaHookInit(); + + return CHIP_NO_ERROR; +} + +void OTAImageProcessorImpl::Clear() +{ + mHeaderParser.Clear(); + mAccumulator.Clear(); + mParams.totalFileBytes = 0; + mParams.downloadedBytes = 0; + mCurrentProcessor = nullptr; + + ReleaseBlock(); +} + +CHIP_ERROR OTAImageProcessorImpl::PrepareDownload() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandlePrepareDownload, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::Finalize() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandleFinalize, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::Apply() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandleApply, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::Abort() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandleAbort, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & block) +{ + if ((block.data() == nullptr) || block.empty()) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + // Store block data for HandleProcessBlock to access + CHIP_ERROR err = SetBlock(block); + if (err != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Cannot set block data: %" CHIP_ERROR_FORMAT, err.Format()); + } + + DeviceLayer::PlatformMgr().ScheduleWork(HandleProcessBlock, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + + VerifyOrReturn(imageProcessor != nullptr, ChipLogError(SoftwareUpdate, "ImageProcessor context is null")); + + VerifyOrReturn(imageProcessor->mDownloader != nullptr, ChipLogError(SoftwareUpdate, "mDownloader is null")); + + GetRequestorInstance()->GetProviderLocation(imageProcessor->mBackupProviderLocation); + + imageProcessor->mHeaderParser.Init(); + imageProcessor->mAccumulator.Init(sizeof(OTATlvHeader)); + imageProcessor->mDownloader->OnPreparedForDownload(CHIP_NO_ERROR); +} + +CHIP_ERROR OTAImageProcessorImpl::ProcessHeader(ByteSpan & block) +{ + OTAImageHeader header; + ReturnErrorOnFailure(mHeaderParser.AccumulateAndDecode(block, header)); + + mParams.totalFileBytes = header.mPayloadSize; + mHeaderParser.Clear(); + ChipLogError(SoftwareUpdate, "Processed header successfully"); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::ProcessPayload(ByteSpan & block) +{ + CHIP_ERROR status = CHIP_NO_ERROR; + + while (true) + { + if (!mCurrentProcessor) + { + ReturnErrorOnFailure(mAccumulator.Accumulate(block)); + ByteSpan tlvHeader{ mAccumulator.data(), sizeof(OTATlvHeader) }; + ReturnErrorOnFailure(SelectProcessor(tlvHeader)); + ReturnErrorOnFailure(mCurrentProcessor->Init()); + } + + status = mCurrentProcessor->Process(block); + if (status == CHIP_ERROR_OTA_CHANGE_PROCESSOR) + { + mAccumulator.Clear(); + mAccumulator.Init(sizeof(OTATlvHeader)); + + mCurrentProcessor = nullptr; + + // If the block size is 0, it means that the processed data was a multiple of + // received BDX block size (e.g. 8 blocks of 1024 bytes were transferred). + // After state for selecting next processor is reset, a request for fetching next + // data must be sent. + if (block.size() == 0) + { + status = CHIP_NO_ERROR; + break; + } + } + else + { + break; + } + } + + return status; +} + +CHIP_ERROR OTAImageProcessorImpl::SelectProcessor(ByteSpan & block) +{ + OTATlvHeader header; + Encoding::LittleEndian::Reader reader(block.data(), sizeof(header)); + + ReturnErrorOnFailure(reader.Read32(&header.tag).StatusCode()); + ReturnErrorOnFailure(reader.Read32(&header.length).StatusCode()); + + auto pair = mProcessorMap.find(header.tag); + if (pair == mProcessorMap.end()) + { + ChipLogError(SoftwareUpdate, "There is no registered processor for tag: %" PRIu32, header.tag); + return CHIP_ERROR_OTA_PROCESSOR_NOT_REGISTERED; + } + + ChipLogDetail(SoftwareUpdate, "Selected processor with tag: %ld", pair->first); + mCurrentProcessor = pair->second; + mCurrentProcessor->SetLength(header.length); + mCurrentProcessor->SetWasSelected(true); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::RegisterProcessor(uint32_t tag, OTATlvProcessor * processor) +{ + auto pair = mProcessorMap.find(tag); + if (pair != mProcessorMap.end()) + { + ChipLogError(SoftwareUpdate, "A processor for tag %" PRIu32 " is already registered.", tag); + return CHIP_ERROR_OTA_PROCESSOR_ALREADY_REGISTERED; + } + + mProcessorMap.insert({ tag, processor }); + + return CHIP_NO_ERROR; +} + +void OTAImageProcessorImpl::HandleAbort(intptr_t context) +{ + ChipLogError(SoftwareUpdate, "OTA was aborted"); + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor != nullptr) + { + imageProcessor->AbortAllProcessors(); + } + imageProcessor->Clear(); + + OtaHookAbort(); +} + +void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + + VerifyOrReturn(imageProcessor != nullptr, ChipLogError(SoftwareUpdate, "ImageProcessor context is null")); + + VerifyOrReturn(imageProcessor->mDownloader != nullptr, ChipLogError(SoftwareUpdate, "mDownloader is null")); + + CHIP_ERROR status; + auto block = ByteSpan(imageProcessor->mBlock.data(), imageProcessor->mBlock.size()); + + if (imageProcessor->mHeaderParser.IsInitialized()) + { + status = imageProcessor->ProcessHeader(block); + if (status != CHIP_NO_ERROR) + { + imageProcessor->HandleStatus(status); + } + } + + status = imageProcessor->ProcessPayload(block); + imageProcessor->HandleStatus(status); +} + +void OTAImageProcessorImpl::HandleStatus(CHIP_ERROR status) +{ + if (status == CHIP_NO_ERROR || status == CHIP_ERROR_BUFFER_TOO_SMALL) + { + mParams.downloadedBytes += mBlock.size(); + FetchNextData(0); + } + else if (status == CHIP_ERROR_OTA_FETCH_ALREADY_SCHEDULED) + { + mParams.downloadedBytes += mBlock.size(); + } + else + { + ChipLogError(SoftwareUpdate, "Image update canceled. Failed to process OTA block: %s", ErrorStr(status)); + GetRequestorInstance()->CancelImageUpdate(); + } +} + +void OTAImageProcessorImpl::AbortAllProcessors() +{ + ChipLogError(SoftwareUpdate, "All selected processors will call abort action"); + + for (auto const & pair : mProcessorMap) + { + if (pair.second->WasSelected()) + { + pair.second->AbortAction(); + pair.second->Clear(); + pair.second->SetWasSelected(false); + } + } +} + +bool OTAImageProcessorImpl::IsFirstImageRun() +{ + OTARequestorInterface * requestor = chip::GetRequestorInstance(); + if (requestor == nullptr) + { + return false; + } + + return requestor->GetCurrentUpdateState() == OTARequestorInterface::OTAUpdateStateEnum::kApplying; +} + +CHIP_ERROR OTAImageProcessorImpl::ConfirmCurrentImage() +{ + uint32_t currentVersion; + uint32_t targetVersion; + + OTARequestorInterface * requestor = chip::GetRequestorInstance(); + ReturnErrorCodeIf(requestor == nullptr, CHIP_ERROR_INTERNAL); + + targetVersion = requestor->GetTargetVersion(); + ReturnErrorOnFailure(DeviceLayer::ConfigurationMgr().GetSoftwareVersion(currentVersion)); + if (currentVersion != targetVersion) + { + ChipLogError(SoftwareUpdate, "Current sw version %" PRIu32 " is different than the expected sw version = %" PRIu32, + currentVersion, targetVersion); + return CHIP_ERROR_INCORRECT_STATE; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::SetBlock(ByteSpan & block) +{ + if (!IsSpanUsable(block)) + { + return CHIP_NO_ERROR; + } + + if (mBlock.size() < block.size()) + { + if (!mBlock.empty()) + { + ReleaseBlock(); + } + uint8_t * mBlock_ptr = static_cast(chip::Platform::MemoryAlloc(block.size())); + if (mBlock_ptr == nullptr) + { + return CHIP_ERROR_NO_MEMORY; + } + mBlock = MutableByteSpan(mBlock_ptr, block.size()); + } + + CHIP_ERROR err = CopySpanToMutableSpan(block, mBlock); + if (err != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Cannot copy block data: %" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + return CHIP_NO_ERROR; +} + +void OTAImageProcessorImpl::HandleFinalize(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + return; + } + + imageProcessor->ReleaseBlock(); +} + +void OTAImageProcessorImpl::HandleApply(intptr_t context) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + return; + } + + for (auto const & pair : imageProcessor->mProcessorMap) + { + if (pair.second->WasSelected()) + { + error = pair.second->ApplyAction(); + if (error != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Apply action for tag %d processor failed.", (uint8_t) pair.first); + // Revert all previously applied actions if current apply action fails. + // Reset image processor and requestor states. + imageProcessor->AbortAllProcessors(); + imageProcessor->Clear(); + GetRequestorInstance()->Reset(); + + return; + } + } + } + + for (auto const & pair : imageProcessor->mProcessorMap) + { + pair.second->Clear(); + pair.second->SetWasSelected(false); + } + + imageProcessor->mAccumulator.Clear(); + + ConfigurationManagerImpl().StoreSoftwareUpdateCompleted(); + PlatformMgr().HandleServerShuttingDown(); + + // Set the necessary information to inform the SSBL that a new image is available + // and trigger the actual device reboot after some time, to take into account + // queued actions, e.g. sending events to a subscription + SystemLayer().StartTimer( + chip::System::Clock::Milliseconds32(CHIP_DEVICE_LAYER_OTA_REBOOT_DELAY), + [](chip::System::Layer *, void *) { OtaHookReset(); }, nullptr); +} + +CHIP_ERROR OTAImageProcessorImpl::ReleaseBlock() +{ + if (mBlock.data() != nullptr) + { + chip::Platform::MemoryFree(mBlock.data()); + } + + mBlock = MutableByteSpan(); + return CHIP_NO_ERROR; +} + +void OTAImageProcessorImpl::FetchNextData(uint32_t context) +{ + auto * imageProcessor = &OTAImageProcessorImpl::GetDefaultInstance(); + SystemLayer().ScheduleLambda([imageProcessor] { + if (imageProcessor->mDownloader) + { + imageProcessor->mDownloader->FetchNextData(); + } + }); +} + +OTAImageProcessorImpl & OTAImageProcessorImpl::GetDefaultInstance() +{ + return gImageProcessor; +} + +} // namespace chip diff --git a/src/platform/nxp/common/legacy/OTAImageProcessorImpl.h b/src/platform/nxp/common/legacy/OTAImageProcessorImpl.h new file mode 100644 index 00000000000000..a30677037ea7f4 --- /dev/null +++ b/src/platform/nxp/common/legacy/OTAImageProcessorImpl.h @@ -0,0 +1,114 @@ +/* + * + * Copyright (c) 2021-2023 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +/* + * OTA hooks that can be overwritten by application. + * Default behavior is implemented as WEAK symbols in platform OtaHooks.cpp. + */ + +/* + * This hook is called at the end of OTAImageProcessorImpl::Init. + * It should generally register the OTATlvProcessor instances. + */ +extern "C" CHIP_ERROR OtaHookInit(); + +/* + * This hook is called at the end of OTAImageProcessorImpl::HandleApply. + * The default implementation saves the internal OTA entry structure and resets the device. + */ +extern "C" void OtaHookReset(); + +/* + * This hook is called at the end of OTAImageProcessorImpl::HandleAbort. + * For example, it can be used to schedule a retry. + */ +extern "C" void OtaHookAbort(); + +namespace chip { + +class OTAImageProcessorImpl : public OTAImageProcessorInterface +{ +public: + using ProviderLocation = chip::OTARequestorInterface::ProviderLocationType; + + CHIP_ERROR Init(OTADownloader * downloader); + void Clear(); + + //////////// OTAImageProcessorInterface Implementation /////////////// + CHIP_ERROR PrepareDownload() override; + CHIP_ERROR Finalize() override; + CHIP_ERROR Apply() override; + CHIP_ERROR Abort() override; + CHIP_ERROR ProcessBlock(ByteSpan & block) override; + bool IsFirstImageRun() override; + CHIP_ERROR ConfirmCurrentImage() override; + + CHIP_ERROR ProcessHeader(ByteSpan & block); + CHIP_ERROR ProcessPayload(ByteSpan & block); + CHIP_ERROR SelectProcessor(ByteSpan & block); + CHIP_ERROR RegisterProcessor(uint32_t tag, OTATlvProcessor * processor); + Optional & GetBackupProvider() { return mBackupProviderLocation; } + + static void FetchNextData(uint32_t context); + static OTAImageProcessorImpl & GetDefaultInstance(); + +private: + //////////// Actual handlers for the OTAImageProcessorInterface /////////////// + static void HandlePrepareDownload(intptr_t context); + static void HandleFinalize(intptr_t context); + static void HandleApply(intptr_t context); + static void HandleAbort(intptr_t context); + static void HandleProcessBlock(intptr_t context); + + void HandleStatus(CHIP_ERROR status); + + /** + * Called to allocate memory for mBlock if necessary and set it to block + */ + CHIP_ERROR SetBlock(ByteSpan & block); + + /** + * Called to release allocated memory for mBlock + */ + CHIP_ERROR ReleaseBlock(); + + /** + * Call AbortAction for all processors that were used + */ + void AbortAllProcessors(); + + MutableByteSpan mBlock; + OTADownloader * mDownloader; + OTAImageHeaderParser mHeaderParser; + OTATlvProcessor * mCurrentProcessor = nullptr; + OTADataAccumulator mAccumulator; + std::map mProcessorMap; + Optional mBackupProviderLocation; +}; + +} // namespace chip diff --git a/src/platform/nxp/common/legacy/OTATlvProcessor.cpp b/src/platform/nxp/common/legacy/OTATlvProcessor.cpp new file mode 100644 index 00000000000000..e50da13cecdd31 --- /dev/null +++ b/src/platform/nxp/common/legacy/OTATlvProcessor.cpp @@ -0,0 +1,178 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#include +#include +#include + +#include +#include +#if OTA_ENCRYPTION_ENABLE +#include "OtaUtils.h" +#include "rom_aes.h" +#endif +namespace chip { + +#if OTA_ENCRYPTION_ENABLE +constexpr uint8_t au8Iv[] = { 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x00, 0x00, 0x00, 0x00 }; +#endif + +CHIP_ERROR OTATlvProcessor::ApplyAction() +{ + return mApplyState == ApplyState::kApply ? CHIP_NO_ERROR : CHIP_ERROR_OTA_PROCESSOR_DO_NOT_APPLY; +} + +CHIP_ERROR OTATlvProcessor::Process(ByteSpan & block) +{ + CHIP_ERROR status = CHIP_NO_ERROR; + uint32_t bytes = chip::min(mLength - mProcessedLength, static_cast(block.size())); + ByteSpan relevantData = block.SubSpan(0, bytes); + + status = ProcessInternal(relevantData); + if (!IsError(status)) + { + mProcessedLength += bytes; + block = block.SubSpan(bytes); + if (mProcessedLength == mLength) + { + status = ExitAction(); + if (!IsError(status)) + { + // If current block was processed fully and the block still contains data, it + // means that the block contains another TLV's data and the current processor + // should be changed by OTAImageProcessorImpl. + return CHIP_ERROR_OTA_CHANGE_PROCESSOR; + } + } + } + + return status; +} + +void OTATlvProcessor::ClearInternal() +{ + mLength = 0; + mProcessedLength = 0; + mWasSelected = false; + mApplyState = ApplyState::kApply; +#if OTA_ENCRYPTION_ENABLE + mIVOffset = 0; +#endif +} + +bool OTATlvProcessor::IsError(CHIP_ERROR & status) +{ + return status != CHIP_NO_ERROR && status != CHIP_ERROR_BUFFER_TOO_SMALL && status != CHIP_ERROR_OTA_FETCH_ALREADY_SCHEDULED; +} + +void OTADataAccumulator::Init(uint32_t threshold) +{ + mThreshold = threshold; + mBufferOffset = 0; + mBuffer.Alloc(mThreshold); +} + +void OTADataAccumulator::Clear() +{ + mThreshold = 0; + mBufferOffset = 0; + mBuffer.Free(); +} + +CHIP_ERROR OTADataAccumulator::Accumulate(ByteSpan & block) +{ + uint32_t numBytes = chip::min(mThreshold - mBufferOffset, static_cast(block.size())); + memcpy(&mBuffer[mBufferOffset], block.data(), numBytes); + mBufferOffset += numBytes; + block = block.SubSpan(numBytes); + + if (mBufferOffset < mThreshold) + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + + return CHIP_NO_ERROR; +} + +#if OTA_ENCRYPTION_ENABLE +CHIP_ERROR OTATlvProcessor::vOtaProcessInternalEncryption(MutableByteSpan & block) +{ + uint8_t iv[16]; + uint8_t key[kOTAEncryptionKeyLength]; + uint8_t dataOut[16] = { 0 }; + uint32_t u32IVCount; + uint32_t Offset = 0; + uint8_t data; + tsReg128 sKey; + aesContext_t Context; + + memcpy(iv, au8Iv, sizeof(au8Iv)); + + u32IVCount = (((uint32_t) iv[12]) << 24) | (((uint32_t) iv[13]) << 16) | (((uint32_t) iv[14]) << 8) | (iv[15]); + u32IVCount += (mIVOffset >> 4); + + iv[12] = (uint8_t) ((u32IVCount >> 24) & 0xff); + iv[13] = (uint8_t) ((u32IVCount >> 16) & 0xff); + iv[14] = (uint8_t) ((u32IVCount >> 8) & 0xff); + iv[15] = (uint8_t) (u32IVCount & 0xff); + + if (Encoding::HexToBytes(OTA_ENCRYPTION_KEY, strlen(OTA_ENCRYPTION_KEY), key, kOTAEncryptionKeyLength) != + kOTAEncryptionKeyLength) + { + // Failed to convert the OTAEncryptionKey string to octstr type value + return CHIP_ERROR_INVALID_STRING_LENGTH; + } + + ByteSpan KEY = ByteSpan(key); + Encoding::LittleEndian::Reader reader_key(KEY.data(), KEY.size()); + ReturnErrorOnFailure(reader_key.Read32(&sKey.u32register0) + .Read32(&sKey.u32register1) + .Read32(&sKey.u32register2) + .Read32(&sKey.u32register3) + .StatusCode()); + + while (Offset + 16 <= block.size()) + { + /*Encrypt the IV*/ + Context.mode = AES_MODE_ECB_ENCRYPT; + Context.pSoftwareKey = (uint32_t *) &sKey; + AES_128_ProcessBlocks(&Context, (uint32_t *) &iv[0], (uint32_t *) &dataOut[0], 1); + + /* Decrypt a block of the buffer */ + for (uint8_t i = 0; i < 16; i++) + { + data = block[Offset + i] ^ dataOut[i]; + memcpy(&block[Offset + i], &data, sizeof(uint8_t)); + } + + /* increment the IV for the next block */ + u32IVCount++; + + iv[12] = (uint8_t) ((u32IVCount >> 24) & 0xff); + iv[13] = (uint8_t) ((u32IVCount >> 16) & 0xff); + iv[14] = (uint8_t) ((u32IVCount >> 8) & 0xff); + iv[15] = (uint8_t) (u32IVCount & 0xff); + + Offset += 16; /* increment the buffer offset */ + mIVOffset += 16; + } + + return CHIP_NO_ERROR; +} +#endif +} // namespace chip diff --git a/src/platform/nxp/common/legacy/OTATlvProcessor.h b/src/platform/nxp/common/legacy/OTATlvProcessor.h new file mode 100644 index 00000000000000..f1faef7e8eecf9 --- /dev/null +++ b/src/platform/nxp/common/legacy/OTATlvProcessor.h @@ -0,0 +1,180 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#pragma once + +#include +#include +#include + +namespace chip { + +#define CHIP_ERROR_TLV_PROCESSOR(e) \ + ChipError(ChipError::Range::kLastRange, ((uint8_t) ChipError::Range::kLastRange << 3) | e, __FILE__, __LINE__) + +#define CHIP_ERROR_OTA_CHANGE_PROCESSOR CHIP_ERROR_TLV_PROCESSOR(0x02) +#define CHIP_ERROR_OTA_PROCESSOR_NOT_REGISTERED CHIP_ERROR_TLV_PROCESSOR(0x03) +#define CHIP_ERROR_OTA_PROCESSOR_ALREADY_REGISTERED CHIP_ERROR_TLV_PROCESSOR(0x04) +#define CHIP_ERROR_OTA_PROCESSOR_CLIENT_INIT CHIP_ERROR_TLV_PROCESSOR(0x05) +#define CHIP_ERROR_OTA_PROCESSOR_MAKE_ROOM CHIP_ERROR_TLV_PROCESSOR(0x06) +#define CHIP_ERROR_OTA_PROCESSOR_PUSH_CHUNK CHIP_ERROR_TLV_PROCESSOR(0x07) +#define CHIP_ERROR_OTA_PROCESSOR_IMG_AUTH CHIP_ERROR_TLV_PROCESSOR(0x08) +#define CHIP_ERROR_OTA_FETCH_ALREADY_SCHEDULED CHIP_ERROR_TLV_PROCESSOR(0x09) +#define CHIP_ERROR_OTA_PROCESSOR_IMG_COMMIT CHIP_ERROR_TLV_PROCESSOR(0x0A) +#define CHIP_ERROR_OTA_PROCESSOR_CB_NOT_REGISTERED CHIP_ERROR_TLV_PROCESSOR(0x0B) +#define CHIP_ERROR_OTA_PROCESSOR_EEPROM_OFFSET CHIP_ERROR_TLV_PROCESSOR(0x0C) +#define CHIP_ERROR_OTA_PROCESSOR_EXTERNAL_STORAGE CHIP_ERROR_TLV_PROCESSOR(0x0D) +#define CHIP_ERROR_OTA_PROCESSOR_START_IMAGE CHIP_ERROR_TLV_PROCESSOR(0x0E) +#define CHIP_ERROR_OTA_PROCESSOR_DO_NOT_APPLY CHIP_ERROR_TLV_PROCESSOR(0x0F) + +// Descriptor constants +constexpr size_t kVersionStringSize = 64; +constexpr size_t kBuildDateSize = 64; + +constexpr uint16_t requestedOtaMaxBlockSize = 1024; + +/** + * Used alongside RegisterDescriptorCallback to register + * a custom descriptor processing function with a certain + * TLV processor. + */ +typedef CHIP_ERROR (*ProcessDescriptor)(void * descriptor); + +struct OTATlvHeader +{ + uint32_t tag; + uint32_t length; +}; + +/** + * This class defines an interface for a Matter TLV processor. + * Instances of derived classes can be registered as processors + * in OTAImageProcessorImpl. Based on the TLV type, a certain + * processor is used to process subsequent blocks until the number + * of bytes found in the metadata is processed. In case a block contains + * data from two different TLVs, the processor should ensure the remaining + * data is returned in the block passed as input. + * The default processors: application, SSBL and factory data are registered + * in OTAImageProcessorImpl::Init through OtaHookInit. + * Applications should use OTAImageProcessorImpl::RegisterProcessor + * to register additional processors. + */ +class OTATlvProcessor +{ +public: + enum class ApplyState : uint8_t + { + kApply = 0, + kDoNotApply + }; + + virtual ~OTATlvProcessor() {} + + virtual CHIP_ERROR Init() = 0; + virtual CHIP_ERROR Clear() = 0; + virtual CHIP_ERROR AbortAction() = 0; + virtual CHIP_ERROR ExitAction() { return CHIP_NO_ERROR; } + virtual CHIP_ERROR ApplyAction(); + + CHIP_ERROR Process(ByteSpan & block); + void RegisterDescriptorCallback(ProcessDescriptor callback) { mCallbackProcessDescriptor = callback; } + void SetLength(uint32_t length) { mLength = length; } + void SetWasSelected(bool selected) { mWasSelected = selected; } + bool WasSelected() { return mWasSelected; } +#if OTA_ENCRYPTION_ENABLE + CHIP_ERROR vOtaProcessInternalEncryption(MutableByteSpan & block); +#endif + +protected: + /** + * @brief Process custom TLV payload + * + * The method takes subsequent chunks of the Matter OTA image file and processes them. + * If more image chunks are needed, CHIP_ERROR_BUFFER_TOO_SMALL error is returned. + * Other error codes indicate that an error occurred during processing. Fetching + * next data is scheduled automatically by OTAImageProcessorImpl if the return value + * is neither an error code, nor CHIP_ERROR_OTA_FETCH_ALREADY_SCHEDULED (which implies the + * scheduling is done inside ProcessInternal or will be done in the future, through a + * callback). + * + * @param block Byte span containing a subsequent Matter OTA image chunk. When the method + * returns CHIP_NO_ERROR, the byte span is used to return a remaining part + * of the chunk, not used by current TLV processor. + * + * @retval CHIP_NO_ERROR Block was processed successfully. + * @retval CHIP_ERROR_BUFFER_TOO_SMALL Provided buffers are insufficient to decode some + * metadata (e.g. a descriptor). + * @retval CHIP_ERROR_OTA_FETCH_ALREADY_SCHEDULED Should be returned if ProcessInternal schedules + * fetching next data (e.g. through a callback). + * @retval Error code Something went wrong. Current OTA process will be + * canceled. + */ + virtual CHIP_ERROR ProcessInternal(ByteSpan & block) = 0; + + void ClearInternal(); + + bool IsError(CHIP_ERROR & status); + +#if OTA_ENCRYPTION_ENABLE + /*ota decryption*/ + uint32_t mIVOffset = 0; + /* Expected byte size of the OTAEncryptionKeyLength */ + static constexpr size_t kOTAEncryptionKeyLength = 16; +#endif + uint32_t mLength = 0; + uint32_t mProcessedLength = 0; + bool mWasSelected = false; + + /** + * @brief A flag to account for corner cases during OTA apply + * + * Used by the default ApplyAction implementation. + * + * If something goes wrong during ExitAction of the TLV processor, + * then mApplyState should be set to kDoNotApply and the image processor + * should abort. In this case, the BDX transfer was already finished + * and calling CancelImageUpdate will not abort the transfer, hence + * the device will reboot even though it should not have. If ApplyAction + * fails during HandleApply, then the process will be aborted. + */ + ApplyState mApplyState = ApplyState::kApply; + ProcessDescriptor mCallbackProcessDescriptor = nullptr; +}; + +/** + * This class can be used to accumulate data until a given threshold. + * Should be used by OTATlvProcessor derived classes if they need + * metadata accumulation (e.g. for custom header decoding). + */ +class OTADataAccumulator +{ +public: + void Init(uint32_t threshold); + void Clear(); + CHIP_ERROR Accumulate(ByteSpan & block); + + inline uint8_t * data() { return mBuffer.Get(); } + inline uint32_t GetThreshold() { return mThreshold; } + +private: + uint32_t mThreshold; + uint32_t mBufferOffset; + Platform::ScopedMemoryBuffer mBuffer; +}; + +} // namespace chip diff --git a/src/platform/nxp/common/legacy/OTA_README.md b/src/platform/nxp/common/legacy/OTA_README.md new file mode 100644 index 00000000000000..0c9715b4610ff8 --- /dev/null +++ b/src/platform/nxp/common/legacy/OTA_README.md @@ -0,0 +1,149 @@ +# K32W OTA + +The OTA processing is now delegated to instances of `OTATlvProcessor` derived +classes. These instances are registered with the `OTAImageProcessorImpl` +instance, which manages the selection of processors that should process the next +blocks, until a full TLV block was transferred. + +The application is able to define its own processors, thus extending the default +OTA functionality. The application can also opt to disable the default +processors (application, SSBL and factory data). + +Please note that if an OTA image containing multiple TLV is transferred, then +the action for each TLV is applied sequentially, If one of the actions fails, +the remaining actions will not be applied and OTA abort is called. TBD: should +all actions be applied only if there is no error? Or should each action be +applied separately? + +## Default processors + +The default processors for K32W0 are already implemented in: + +- `OTAFirmwareProcessor` for application/SSBL update. Enabled by default. +- `OTAFactoryDataProcessor` for factory data update. Disabled by default, user + has to specify `chip_ota_enable_factory_data_processor=1` in the build args. + +Some SDK OTA module flags are defined to support additional features: + +- `gOTAAllowCustomStartAddress=1` - enable `EEPROM` offset value. Used + internally by SDK OTA module. +- `gOTAUseCustomOtaEntry=1` - support custom OTA entry for multi-image. +- `gOTACustomOtaEntryMemory=1` - K32W0 uses `OTACustomStorage_ExtFlash` (1) by + default. + +## Implementing custom processors + +A custom processor should implement the abstract interface defined in +`OTATlvProcessor.h`. Below is a compact version: + +``` +class OTATlvProcessor +{ +public: + virtual CHIP_ERROR Init() = 0; + virtual CHIP_ERROR Clear() = 0; + virtual CHIP_ERROR ApplyAction() = 0; + virtual CHIP_ERROR AbortAction() = 0; + virtual CHIP_ERROR ExitAction(); + + CHIP_ERROR Process(ByteSpan & block); + void RegisterDescriptorCallback(ProcessDescriptor callback); +protected: + virtual CHIP_ERROR ProcessInternal(ByteSpan & block) = 0; +}; + +``` + +Some details regarding the interface: + +- `Init` will be called whenever the processor is selected. +- `Clear` will be called when abort occurs or after the apply action takes + place. +- `ApplyAction` will be called in `OTAImageProcessorImpl::HandleApply`, before + the board is reset. +- `AbortAction` will be called in `OTAImageProcessorImpl::HandleAbort`. + Processors should reset state here. +- `ExitAction` is optional and should be implemented by the processors that + want to execute an action after all data has been transferred, but before + `HandleApply` is called. It's called before the new processor selection + takes place. This is useful in the context of multiple TLV transferred in a + single OTA process. +- `Process` is the public API used inside `OTAImageProcessorImpl` for data + processing. This is a wrapper over `ProcessInternal`, which can return + `CHIP_OTA_CHANGE_PROCESSOR` to notify a new processor should be selected for + the remaining data. +- `RegisterDescriptorCallback` can be used to register a callback for + processing the descriptor. It's optional. +- `ProcessInternal` should return: _ `CHIP_NO_ERROR` if block was processed + successfully. _ `CHIP_ERROR_BUFFER_TOO_SMALL` if current block doesn't + contain all necessary data. This can happen when a TLV value field has a + header, but it is split across two blocks. \* + `CHIP_OTA_FETCH_ALREADY_SCHEDULED` if block was processed successfully and + the fetching is already scheduled by the processor. This happens in the + default application processor, because the next data fetching is scheduled + through a callback (called when enough external flash was erased). + +Furthermore, a processor can use an instance of `OTADataAccumulator` to +accumulate data until a given threshold. This is useful when a custom payload +contains metadata that need parsing: accumulate data until the threshold is +reached or return `CHIP_ERROR_BUFFER_TOO_SMALL` to signal +`OTAImageProcessorImpl` more data is needed. + +``` +/** + * This class can be used to accumulate data until a given threshold. + * Should be used by OTATlvProcessor derived classes if they need + * metadata accumulation (e.g. for custom header decoding). + */ +class OTADataAccumulator +{ +public: + void Init(uint32_t threshold); + void Clear(); + CHIP_ERROR Accumulate(ByteSpan & block); + + inline uint8_t* data() { return mBuffer.Get(); } + +private: + uint32_t mThreshold; + uint32_t mBufferOffset; + Platform::ScopedMemoryBuffer mBuffer; +}; +``` + +## SSBL max entries example + +`CONFIG_CHIP_K32W0_MAX_ENTRIES_TEST` can be set to 1 to enable max entries test. +There will be 8 additional processors registered in default `OtaHooks` +implementation. The OTA image should be generated with the +`create_ota_images.sh` script from `./scripts/tools/nxp/ota/examples`. + +## Factory data restore mechanism + +Prior to factory data update, the old factory data is backed up in external +flash. If anything interrupts the update (e.g. power loss), there is a slight +chance the internal flash factory data section is erased and has to be restored +at next boot. The `FactoryDataProvider` offers a default restore mechanism and +support for registering additional restore mechanisms or overwriting the default +one. + +Prior to factory data update, the old factory data is backed up in external +flash. If anything interrupts the update (e.g. power loss), there is a slight +chance the internal flash factory data section is erased and has to be restored +at next boot. The `FactoryDataProvider` offers a default restore mechanism and +support for registering additional restore mechanisms or overwriting the default +one. + +Restore mechanisms are just functions that have this signature: +`CHIP_ERROR (*)(void)`. Any such function can be registered through +`FactoryDataProvider::RegisterRestoreMechanism`. + +The default restore mechanism is implemented as a weak function: +`FactoryDataDefaultRestoreMechanism`. It is registered in +`FactoryDataProvider::Init`, before factory data validation, and it can be +overwritten at application level. When doing the actual restore, the mechanisms +are called in the order they were registered. + +Please note that the restore mechanisms registration order matters. Once a +restore mechanism is successful (`CHIP_NO_ERROR` is returned), the restore +process has finished and subsequent restore mechanisms will not be called. diff --git a/src/platform/nxp/k32w/k32w0/DefaultTestEventTriggerDelegate.cpp b/src/platform/nxp/k32w/k32w0/DefaultTestEventTriggerDelegate.cpp deleted file mode 100644 index 69935bb024559d..00000000000000 --- a/src/platform/nxp/k32w/k32w0/DefaultTestEventTriggerDelegate.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * - * Copyright (c) 2022 Project CHIP Authors - * All rights reserved. - * - * 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. - */ - -#include "DefaultTestEventTriggerDelegate.h" - -#include -#include - -namespace chip { - -bool DefaultTestEventTriggerDelegate::DoesEnableKeyMatch(const ByteSpan & enableKey) const -{ - return !mEnableKey.empty() && mEnableKey.data_equal(enableKey); -} - -} // namespace chip diff --git a/src/platform/nxp/k32w/k32w0/DefaultTestEventTriggerDelegate.h b/src/platform/nxp/k32w/k32w0/DefaultTestEventTriggerDelegate.h deleted file mode 100644 index 0bfd4c5b0fa725..00000000000000 --- a/src/platform/nxp/k32w/k32w0/DefaultTestEventTriggerDelegate.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * - * Copyright (c) 2022 Project CHIP Authors - * All rights reserved. - * - * 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. - */ - -#pragma once - -#include - -namespace chip { - -class DefaultTestEventTriggerDelegate : public TestEventTriggerDelegate -{ -public: - explicit DefaultTestEventTriggerDelegate(const ByteSpan & enableKey) : mEnableKey(enableKey) {} - - bool DoesEnableKeyMatch(const ByteSpan & enableKey) const override; - -private: - ByteSpan mEnableKey; -}; - -} // namespace chip diff --git a/src/platform/nxp/k32w/k32w0/BLEManagerImpl.cpp b/src/platform/nxp/k32w0/BLEManagerImpl.cpp similarity index 98% rename from src/platform/nxp/k32w/k32w0/BLEManagerImpl.cpp rename to src/platform/nxp/k32w0/BLEManagerImpl.cpp index af56961cf23dc1..aa56e06a8d5598 100644 --- a/src/platform/nxp/k32w/k32w0/BLEManagerImpl.cpp +++ b/src/platform/nxp/k32w0/BLEManagerImpl.cpp @@ -37,7 +37,7 @@ osaEventId_t mControllerTaskEvent; extern msgQueue_t gApp2Host_TaskQueue; extern msgQueue_t gHci2Host_TaskQueue; -#include +#include extern "C" bool_t Ble_ConfigureHostStackConfig(void); diff --git a/src/platform/nxp/k32w/k32w0/BLEManagerImpl.h b/src/platform/nxp/k32w0/BLEManagerImpl.h similarity index 97% rename from src/platform/nxp/k32w/k32w0/BLEManagerImpl.h rename to src/platform/nxp/k32w0/BLEManagerImpl.h index eb8a25804804d1..686eb1e3f703ee 100644 --- a/src/platform/nxp/k32w/k32w0/BLEManagerImpl.h +++ b/src/platform/nxp/k32w0/BLEManagerImpl.h @@ -25,7 +25,7 @@ #include "ble_host_task_config.h" #include "controller_interface.h" -#include +#include /* host task configuration */ #define HOST_TASK_PRIORITY (4U) diff --git a/src/platform/nxp/k32w/k32w0/BUILD.gn b/src/platform/nxp/k32w0/BUILD.gn similarity index 77% rename from src/platform/nxp/k32w/k32w0/BUILD.gn rename to src/platform/nxp/k32w0/BUILD.gn index 76af2760bc9051..41a80a77a7aa53 100644 --- a/src/platform/nxp/k32w/k32w0/BUILD.gn +++ b/src/platform/nxp/k32w0/BUILD.gn @@ -19,17 +19,18 @@ import("${chip_root}/src/platform/device.gni") import("${nxp_sdk_build_root}/${nxp_sdk_name}/${nxp_sdk_name}.gni") assert(chip_device_platform == "nxp") -assert(nxp_platform == "k32w/k32w0") +assert(nxp_platform == "k32w0") if (chip_enable_openthread) { import("//build_overrides/openthread.gni") } static_library("nxp_platform") { + defines = [] sources = [ - "../../../SingletonConfigurationManager.cpp", - "../common/BLEManagerCommon.cpp", - "../common/BLEManagerCommon.h", + "../../SingletonConfigurationManager.cpp", + "../common/legacy/BLEManagerCommon.cpp", + "../common/legacy/BLEManagerCommon.h", "BLEManagerImpl.cpp", "BLEManagerImpl.h", "CHIPDevicePlatformConfig.h", @@ -38,8 +39,6 @@ static_library("nxp_platform") { "ConfigurationManagerImpl.h", "ConnectivityManagerImpl.cpp", "ConnectivityManagerImpl.h", - "DefaultTestEventTriggerDelegate.cpp", - "DefaultTestEventTriggerDelegate.h", "DiagnosticDataProviderImpl.cpp", "DiagnosticDataProviderImpl.h", "K32W0Config.cpp", @@ -60,12 +59,12 @@ static_library("nxp_platform") { "${chip_root}/src/credentials/examples/DeviceAttestationCredsExample.h", "${chip_root}/src/credentials/examples/ExampleDACs.h", "${chip_root}/src/credentials/examples/ExamplePAI.h", - "${chip_root}/src/platform/nxp/k32w/k32w0/BLEManagerImpl.h", + "${chip_root}/src/platform/nxp/k32w0/BLEManagerImpl.h", ] if (chip_with_factory_data == 1) { sources += [ - "../common/FactoryDataProvider.cpp", + "FactoryDataProvider.cpp", "FactoryDataProviderImpl.cpp", ] public += [ @@ -79,13 +78,13 @@ static_library("nxp_platform") { } if (chip_enable_ota_requestor) { - public += [ "../common/OTAImageProcessorImpl.h" ] + public += [ "../common/legacy/OTAImageProcessorImpl.h" ] sources += [ - "../common/OTAImageProcessorImpl.cpp", - "../common/OTAImageProcessorImpl.h", - "../common/OTATlvProcessor.cpp", - "../common/OTATlvProcessor.h", + "../common/legacy/OTAImageProcessorImpl.cpp", + "../common/legacy/OTAImageProcessorImpl.h", + "../common/legacy/OTATlvProcessor.cpp", + "../common/legacy/OTATlvProcessor.h", ] if (chip_enable_ota_firmware_processor == 1) { @@ -107,10 +106,7 @@ static_library("nxp_platform") { deps = [ "${chip_root}/src/platform/logging:headers" ] - public_deps = [ - "${chip_root}/src/app:test-event-trigger", - "${chip_root}/src/platform:platform_base", - ] + public_deps = [ "${chip_root}/src/platform:platform_base" ] if (chip_crypto == "platform") { if (chip_crypto_flavor == "tinycrypt") { @@ -120,7 +116,7 @@ static_library("nxp_platform") { } if (chip_crypto_flavor == "NXP-Ultrafast-P256") { - sources += [ "${chip_root}/src/platform/nxp/k32w/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp" ] + sources += [ "${chip_root}/src/platform/nxp/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp" ] public_deps += [ "${mbedtls_root}:mbedtls", @@ -131,16 +127,16 @@ static_library("nxp_platform") { if (chip_enable_openthread) { sources += [ - "../../../OpenThread/OpenThreadUtils.cpp", + "../../OpenThread/OpenThreadUtils.cpp", "ThreadStackManagerImpl.cpp", "ThreadStackManagerImpl.h", ] if (chip_mdns == "platform") { sources += [ - "../../../OpenThread/DnssdImpl.cpp", - "../../../OpenThread/OpenThreadDnssdImpl.cpp", - "../../../OpenThread/OpenThreadDnssdImpl.h", + "../../OpenThread/DnssdImpl.cpp", + "../../OpenThread/OpenThreadDnssdImpl.cpp", + "../../OpenThread/OpenThreadDnssdImpl.h", ] deps += [ "${chip_root}/src/lib/dnssd:platform_header" ] } diff --git a/src/platform/nxp/k32w/k32w0/BlePlatformConfig.h b/src/platform/nxp/k32w0/BlePlatformConfig.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/BlePlatformConfig.h rename to src/platform/nxp/k32w0/BlePlatformConfig.h diff --git a/src/platform/nxp/k32w/k32w0/CHIPDevicePlatformConfig.h b/src/platform/nxp/k32w0/CHIPDevicePlatformConfig.h similarity index 97% rename from src/platform/nxp/k32w/k32w0/CHIPDevicePlatformConfig.h rename to src/platform/nxp/k32w0/CHIPDevicePlatformConfig.h index faa283ffbe41dc..523d6e8941232d 100644 --- a/src/platform/nxp/k32w/k32w0/CHIPDevicePlatformConfig.h +++ b/src/platform/nxp/k32w0/CHIPDevicePlatformConfig.h @@ -135,14 +135,14 @@ #endif // CONFIG_CHIP_K32W0_KVS_MOVE_KEYS_TO_SPECIFIC_STORAGE /** - * @def CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR + * @def CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR * * Enables default OTA TLV factory data processor. * Disabled by default. */ -#ifndef CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR -#define CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR 0 -#endif // CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#ifndef CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR +#define CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR 0 +#endif // CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR /** * @def CHIP_DEVICE_LAYER_ENABLE_PDM_LOGS @@ -211,4 +211,4 @@ #define CHIP_DEVICE_CONFIG_ENABLE_TEST_SETUP_PARAMS 1 -#include +#include diff --git a/src/platform/nxp/k32w/k32w0/CHIPDevicePlatformEvent.h b/src/platform/nxp/k32w0/CHIPDevicePlatformEvent.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/CHIPDevicePlatformEvent.h rename to src/platform/nxp/k32w0/CHIPDevicePlatformEvent.h diff --git a/src/platform/nxp/k32w0/CHIPDevicePlatformRamStorageConfig.h b/src/platform/nxp/k32w0/CHIPDevicePlatformRamStorageConfig.h new file mode 100644 index 00000000000000..51ee8c4d27ee79 --- /dev/null +++ b/src/platform/nxp/k32w0/CHIPDevicePlatformRamStorageConfig.h @@ -0,0 +1,185 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +/** + * @file + * Configuration of RAM storage metadata: key IDs and NVM IDs. + */ + +#pragma once + +/* Base key IDs used when creating new keys for RAM storage instances. */ +/** + * @def kKeyId_Factory + * + * Base key id used for factory RAM storage. + */ +#ifndef kKeyId_Factory +#define kKeyId_Factory (uint8_t) 0x01 +#endif + +/** + * @def kKeyId_Config + * + * Base key id used for config RAM storage. + */ +#ifndef kKeyId_Config +#define kKeyId_Config (uint8_t) 0x02 +#endif + +/** + * @def kKeyId_Counter + * + * Base key id used for counter RAM storage. + */ +#ifndef kKeyId_Counter +#define kKeyId_Counter (uint8_t) 0x03 +#endif + +/** + * @def kKeyId_KvsKeys + * + * Base key id used for KVS keys RAM storage. + */ +#ifndef kKeyId_KvsKeys +#define kKeyId_KvsKeys (uint8_t) 0x04 +#endif + +/** + * @def kKeyId_KvsValues + * + * Base key id used for KVS values RAM storage. + */ +#ifndef kKeyId_KvsValues +#define kKeyId_KvsValues (uint8_t) 0x05 +#endif + +/* PDM IDs used when defining RAM storage instances or RAM buffers (OT). */ +/** + * @def kNvmId_Factory + * + * PDM ID used for factory RAM storage. + */ +#ifndef kNvmId_Factory +#define kNvmId_Factory (uint16_t) 0x5001 +#endif + +/** + * @def kNvmId_Config + * + * PDM ID used for config RAM storage. + */ +#ifndef kNvmId_Config +#define kNvmId_Config (uint16_t) 0x5002 +#endif + +/** + * @def kNvmId_Counter + * + * PDM ID used for counter RAM storage. + */ +#ifndef kNvmId_Counter +#define kNvmId_Counter (uint16_t) 0x5003 +#endif + +/** + * @def kNvmId_KvsKeys + * + * PDM ID used for KVS keys RAM storage. + */ +#ifndef kNvmId_KvsKeys +#define kNvmId_KvsKeys (uint16_t) 0x6000 +#endif + +/** + * @def kNvmId_KvsValues + * + * PDM ID used for KVS values RAM storage. + * KVS buffer can become quite big, so this PDM + * id is used as base id for subsequent PDM ids + * used to store data in chunks of PDM page size. + * This will use the extended search feature, so + * subsequent PDM ids should not be used. + */ +#ifndef kNvmId_KvsValues +#define kNvmId_KvsValues (uint16_t) 0x6001 +#endif + +/** + * @def kNvmId_KvsSubscription + * + * PDM ID used for KVS subscription RAM storage. + * It will store both keys and values for those keys. + */ +#ifndef kNvmId_KvsSubscription +#define kNvmId_KvsSubscription (uint16_t) 0x6100 +#endif + +/** + * @def kNvmId_KvsGroups + * + * PDM ID used for KVS groups RAM storage. + * It will store both keys and values for those keys. + * This will use the extended search feature, so + * subsequent PDM ids should not be used. + */ +#ifndef kNvmId_KvsGroups +#define kNvmId_KvsGroups (uint16_t) 0x6200 +#endif + +/** + * @def kNvmId_KvsAcl + * + * PDM ID used for KVS groups RAM storage. + * It will store both keys and values for those keys. + * This will use the extended search feature, so + * subsequent PDM ids should not be used. + */ +#ifndef kNvmId_KvsAcl +#define kNvmId_KvsAcl (uint16_t) 0x6300 +#endif + +/** + * @def kNvmId_OTConfigData + * + * PDM ID used for OT RAM buffer. + */ +#ifndef kNvmId_OTConfigData +#define kNvmId_OTConfigData (uint16_t) 0x4F00 +#endif + +/** + * @def kNvmId_ApplicationBase + * + * Base PDM ID to be used by applications to define their own + * PDM IDs by using an offset. + */ +#ifndef kNvmId_ApplicationBase +#define kNvmId_ApplicationBase (uint16_t) 0xA000 +#endif + +#if CONFIG_CHIP_LOAD_REAL_FACTORY_DATA +/** + * @def kNvmId_FactoryDataBackup + * + * PDM ID used for factory data backup in FactoryDataProvider. + */ +#ifndef kNvmId_FactoryDataBackup +#define kNvmId_FactoryDataBackup (uint16_t) 0x7000 +#endif +#endif // CONFIG_CHIP_LOAD_REAL_FACTORY_DATA diff --git a/src/platform/nxp/k32w/k32w0/CHIPPlatformConfig.h b/src/platform/nxp/k32w0/CHIPPlatformConfig.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/CHIPPlatformConfig.h rename to src/platform/nxp/k32w0/CHIPPlatformConfig.h diff --git a/src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.cpp b/src/platform/nxp/k32w0/ConfigurationManagerImpl.cpp similarity index 98% rename from src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.cpp rename to src/platform/nxp/k32w0/ConfigurationManagerImpl.cpp index b8477051faeade..7343c75b5d5865 100644 --- a/src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.cpp +++ b/src/platform/nxp/k32w0/ConfigurationManagerImpl.cpp @@ -29,8 +29,8 @@ #include #include #include -#include -#include +#include +#include #include "fsl_power.h" #include "fsl_reset.h" diff --git a/src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.h b/src/platform/nxp/k32w0/ConfigurationManagerImpl.h similarity index 98% rename from src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.h rename to src/platform/nxp/k32w0/ConfigurationManagerImpl.h index 8fded100d00a87..c7cf2366ca97cb 100644 --- a/src/platform/nxp/k32w/k32w0/ConfigurationManagerImpl.h +++ b/src/platform/nxp/k32w0/ConfigurationManagerImpl.h @@ -26,7 +26,7 @@ #pragma once #include -#include +#include namespace chip { namespace DeviceLayer { diff --git a/src/platform/nxp/k32w/k32w0/ConnectivityManagerImpl.cpp b/src/platform/nxp/k32w0/ConnectivityManagerImpl.cpp similarity index 100% rename from src/platform/nxp/k32w/k32w0/ConnectivityManagerImpl.cpp rename to src/platform/nxp/k32w0/ConnectivityManagerImpl.cpp diff --git a/src/platform/nxp/k32w/k32w0/ConnectivityManagerImpl.h b/src/platform/nxp/k32w0/ConnectivityManagerImpl.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/ConnectivityManagerImpl.h rename to src/platform/nxp/k32w0/ConnectivityManagerImpl.h diff --git a/src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.cpp b/src/platform/nxp/k32w0/DiagnosticDataProviderImpl.cpp similarity index 99% rename from src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.cpp rename to src/platform/nxp/k32w0/DiagnosticDataProviderImpl.cpp index b3e02f3f64cb71..8cf924d1a63424 100644 --- a/src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.cpp +++ b/src/platform/nxp/k32w0/DiagnosticDataProviderImpl.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #if CHIP_SYSTEM_CONFIG_USE_LWIP #include diff --git a/src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.h b/src/platform/nxp/k32w0/DiagnosticDataProviderImpl.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/DiagnosticDataProviderImpl.h rename to src/platform/nxp/k32w0/DiagnosticDataProviderImpl.h diff --git a/src/platform/nxp/k32w0/FactoryDataProvider.cpp b/src/platform/nxp/k32w0/FactoryDataProvider.cpp new file mode 100644 index 00000000000000..23f8ffe7c0586b --- /dev/null +++ b/src/platform/nxp/k32w0/FactoryDataProvider.cpp @@ -0,0 +1,368 @@ +/* + * + * Copyright (c) 2022 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. + */ + +#if (!CONFIG_CHIP_LOAD_REAL_FACTORY_DATA || !(defined CONFIG_CHIP_LOAD_REAL_FACTORY_DATA)) +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace chip { +namespace DeviceLayer { + +static constexpr size_t kSpake2pSerializedVerifier_MaxBase64Len = + BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_VerifierSerialized_Length) + 1; +static constexpr size_t kSpake2pSalt_MaxBase64Len = BASE64_ENCODED_LEN(chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length) + 1; +/* Secure subsystem private key blob size is 32 + 24 = 56. + * DAC private key may be used to store an SSS exported blob instead of the private key. + */ +static constexpr size_t kDacPrivateKey_MaxLen = Crypto::kP256_PrivateKey_Length + 24; + +uint32_t FactoryDataProvider::kFactoryDataStart = (uint32_t) __MATTER_FACTORY_DATA_START; +uint32_t FactoryDataProvider::kFactoryDataSize = (uint32_t) __MATTER_FACTORY_DATA_SIZE; +uint32_t FactoryDataProvider::kFactoryDataPayloadStart = kFactoryDataStart + sizeof(FactoryDataProvider::Header); + +FactoryDataProvider::~FactoryDataProvider() {} + +CHIP_ERROR FactoryDataProvider::Validate() +{ + uint8_t output[Crypto::kSHA256_Hash_Length] = { 0 }; + + memcpy(&mHeader, (void *) kFactoryDataStart, sizeof(Header)); + ReturnErrorCodeIf(mHeader.hashId != kHashId, CHIP_FACTORY_DATA_HASH_ID); + + ReturnErrorOnFailure(Crypto::Hash_SHA256((uint8_t *) kFactoryDataPayloadStart, mHeader.size, output)); + ReturnErrorCodeIf(memcmp(output, mHeader.hash, kHashLen) != 0, CHIP_FACTORY_DATA_SHA_CHECK); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, + uint32_t * offset) +{ + uint32_t addr = kFactoryDataPayloadStart; + uint8_t type = 0; + + while (addr < (kFactoryDataPayloadStart + mHeader.size)) + { + memcpy(&type, (void *) addr, sizeof(type)); + memcpy(&length, (void *) (addr + 1), sizeof(length)); + + if (searchedType == type) + { + ReturnErrorCodeIf(bufLength < length, CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(pBuf, (void *) (addr + kValueOffset), length); + + if (offset) + *offset = (addr - kFactoryDataPayloadStart); + + return CHIP_NO_ERROR; + } + else + { + /* Jump past 3 bytes of length and then use length to jump to next data */ + addr = addr + kValueOffset + length; + } + } + + return CHIP_ERROR_NOT_FOUND; +} + +CHIP_ERROR FactoryDataProvider::GetCertificationDeclaration(MutableByteSpan & outBuffer) +{ +#if CHIP_USE_DEVICE_CONFIG_CERTIFICATION_DECLARATION + constexpr uint8_t kCdForAllExamples[] = CHIP_DEVICE_CONFIG_CERTIFICATION_DECLARATION; + + return CopySpanToMutableSpan(ByteSpan{ kCdForAllExamples }, outBuffer); +#else + uint16_t declarationSize = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kCertDeclarationId, outBuffer.data(), outBuffer.size(), declarationSize)); + outBuffer.reduce_size(declarationSize); + + return CHIP_NO_ERROR; +#endif +} + +CHIP_ERROR FactoryDataProvider::GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) +{ + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetDeviceAttestationCert(MutableByteSpan & outBuffer) +{ + uint16_t certificateSize = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kDacCertificateId, outBuffer.data(), outBuffer.size(), certificateSize)); + outBuffer.reduce_size(certificateSize); + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductAttestationIntermediateCert(MutableByteSpan & outBuffer) +{ + uint16_t certificateSize = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kPaiCertificateId, outBuffer.data(), outBuffer.size(), certificateSize)); + outBuffer.reduce_size(certificateSize); + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::SignWithDeviceAttestationKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer) +{ + return SignWithDacKey(messageToSign, outSignBuffer); +} + +CHIP_ERROR FactoryDataProvider::GetSetupDiscriminator(uint16_t & setupDiscriminator) +{ + uint32_t discriminator = 0; + uint16_t temp = 0; + + ReturnErrorOnFailure(SearchForId(FactoryDataId::kDiscriminatorId, (uint8_t *) &discriminator, sizeof(discriminator), temp)); + setupDiscriminator = (uint16_t) (discriminator & 0x0000FFFF); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::SetSetupDiscriminator(uint16_t setupDiscriminator) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR FactoryDataProvider::GetSpake2pIterationCount(uint32_t & iterationCount) +{ + uint16_t temp = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kIcId, (uint8_t *) &iterationCount, sizeof(iterationCount), temp)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetSpake2pSalt(MutableByteSpan & saltBuf) +{ + char saltB64[kSpake2pSalt_MaxBase64Len] = { 0 }; + uint16_t saltB64Len = 0; + + ReturnErrorOnFailure(SearchForId(FactoryDataId::kSaltId, (uint8_t *) (&saltB64[0]), sizeof(saltB64), saltB64Len)); + size_t saltLen = chip::Base64Decode32(saltB64, saltB64Len, reinterpret_cast(saltB64)); + + ReturnErrorCodeIf(saltLen > saltBuf.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(saltBuf.data(), saltB64, saltLen); + saltBuf.reduce_size(saltLen); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetSpake2pVerifier(MutableByteSpan & verifierBuf, size_t & verifierLen) +{ + char verifierB64[kSpake2pSerializedVerifier_MaxBase64Len] = { 0 }; + uint16_t verifierB64Len = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kVerifierId, (uint8_t *) &verifierB64[0], sizeof(verifierB64), verifierB64Len)); + + verifierLen = chip::Base64Decode32(verifierB64, verifierB64Len, reinterpret_cast(verifierB64)); + ReturnErrorCodeIf(verifierLen > verifierBuf.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(verifierBuf.data(), verifierB64, verifierLen); + verifierBuf.reduce_size(verifierLen); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetSetupPasscode(uint32_t & setupPasscode) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kSetupPasscodeId, (uint8_t *) &setupPasscode, sizeof(setupPasscode), length)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::SetSetupPasscode(uint32_t setupPasscode) +{ + return CHIP_ERROR_NOT_IMPLEMENTED; +} + +CHIP_ERROR FactoryDataProvider::GetVendorName(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kVendorNameId, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetVendorId(uint16_t & vendorId) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kVidId, (uint8_t *) &vendorId, sizeof(vendorId), length)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductName(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kProductNameId, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductId(uint16_t & productId) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kPidId, (uint8_t *) &productId, sizeof(productId), length)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetPartNumber(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kPartNumber, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductURL(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kProductURL, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductLabel(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kProductLabel, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetSerialNumber(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kSerialNumberId, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) +{ + uint16_t length = 0; + uint8_t date[ConfigurationManager::kMaxManufacturingDateLength]; + + ReturnErrorOnFailure( + SearchForId(FactoryDataId::kManufacturingDateId, date, ConfigurationManager::kMaxManufacturingDateLength, length)); + date[length] = '\0'; + + if (length == 10 && isdigit(date[0]) && isdigit(date[1]) && isdigit(date[2]) && isdigit(date[3]) && date[4] == '-' && + isdigit(date[5]) && isdigit(date[6]) && date[7] == '-' && isdigit(date[8]) && isdigit(date[9])) + { + year = 1000 * (date[0] - '0') + 100 * (date[1] - '0') + 10 * (date[2] - '0') + date[3] - '0'; + month = 10 * (date[5] - '0') + date[6] - '0'; + day = 10 * (date[8] - '0') + date[9] - '0'; + } + else + { + ChipLogError(DeviceLayer, "Manufacturing date is not formatted correctly: YYYY-MM-DD."); + return CHIP_ERROR_INVALID_ARGUMENT; + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetHardwareVersion(uint16_t & hardwareVersion) +{ + uint16_t length = 0; + ReturnErrorOnFailure( + SearchForId(FactoryDataId::kHardwareVersionId, (uint8_t *) &hardwareVersion, sizeof(hardwareVersion), length)); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetHardwareVersionString(char * buf, size_t bufSize) +{ + uint16_t length = 0; + ReturnErrorOnFailure(SearchForId(FactoryDataId::kHardwareVersionStrId, (uint8_t *) buf, bufSize, length)); + buf[length] = '\0'; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) +{ + CHIP_ERROR err = CHIP_ERROR_NOT_IMPLEMENTED; +#if CHIP_ENABLE_ROTATING_DEVICE_ID + static_assert(ConfigurationManager::kRotatingDeviceIDUniqueIDLength >= ConfigurationManager::kMinRotatingDeviceIDUniqueIDLength, + "Length of unique ID for rotating device ID is smaller than minimum."); + uint16_t uniqueIdLen = 0; + err = SearchForId(FactoryDataId::kUniqueId, (uint8_t *) uniqueIdSpan.data(), uniqueIdSpan.size(), uniqueIdLen); +#if defined(CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID) + if (err != CHIP_NO_ERROR) + { + constexpr uint8_t uniqueId[] = CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID; + + ReturnErrorCodeIf(sizeof(uniqueId) > uniqueIdSpan.size(), CHIP_ERROR_BUFFER_TOO_SMALL); + memcpy(uniqueIdSpan.data(), uniqueId, sizeof(uniqueId)); + uniqueIdLen = sizeof(uniqueId); + err = CHIP_NO_ERROR; + } +#endif // CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID + ReturnErrorOnFailure(err); + uniqueIdSpan.reduce_size(uniqueIdLen); +#endif + + return err; +} + +CHIP_ERROR FactoryDataProvider::GetProductFinish(app::Clusters::BasicInformation::ProductFinishEnum * finish) +{ + uint8_t productFinish; + uint16_t length = 0; + auto err = SearchForId(FactoryDataId::kProductFinish, &productFinish, sizeof(productFinish), length); + ReturnErrorCodeIf(err != CHIP_NO_ERROR, CHIP_ERROR_NOT_IMPLEMENTED); + + *finish = static_cast(productFinish); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR FactoryDataProvider::GetProductPrimaryColor(app::Clusters::BasicInformation::ColorEnum * primaryColor) +{ + uint8_t color; + uint16_t length = 0; + auto err = SearchForId(FactoryDataId::kProductPrimaryColor, &color, sizeof(color), length); + ReturnErrorCodeIf(err != CHIP_NO_ERROR, CHIP_ERROR_NOT_IMPLEMENTED); + + *primaryColor = static_cast(color); + + return CHIP_NO_ERROR; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w0/FactoryDataProvider.h b/src/platform/nxp/k32w0/FactoryDataProvider.h new file mode 100644 index 00000000000000..8a76a84800baab --- /dev/null +++ b/src/platform/nxp/k32w0/FactoryDataProvider.h @@ -0,0 +1,158 @@ +/* + * + * Copyright (c) 2022 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. + */ +#pragma once + +#include +#include +#include +#include + +#include + +#include "CHIPPlatformConfig.h" + +#include + +/* Grab symbol for the base address from the linker file. */ +extern uint32_t __MATTER_FACTORY_DATA_START[]; +extern uint32_t __MATTER_FACTORY_DATA_SIZE[]; + +namespace chip { +namespace DeviceLayer { + +#define CHIP_FACTORY_DATA_ERROR(e) \ + ChipError(ChipError::Range::kLastRange, ((uint8_t) ChipError::Range::kLastRange << 2) | e, __FILE__, __LINE__) + +#define CHIP_FACTORY_DATA_SHA_CHECK CHIP_FACTORY_DATA_ERROR(0x01) +#define CHIP_FACTORY_DATA_HEADER_READ CHIP_FACTORY_DATA_ERROR(0x02) +#define CHIP_FACTORY_DATA_HASH_ID CHIP_FACTORY_DATA_ERROR(0x03) +#define CHIP_FACTORY_DATA_PDM_RESTORE CHIP_FACTORY_DATA_ERROR(0x04) +#define CHIP_FACTORY_DATA_NULL CHIP_FACTORY_DATA_ERROR(0x05) +#define CHIP_FACTORY_DATA_FLASH_ERASE CHIP_FACTORY_DATA_ERROR(0x06) +#define CHIP_FACTORY_DATA_FLASH_PROGRAM CHIP_FACTORY_DATA_ERROR(0x07) +#define CHIP_FACTORY_DATA_INTERNAL_FLASH_READ CHIP_FACTORY_DATA_ERROR(0x08) +#define CHIP_FACTORY_DATA_PDM_SAVE_RECORD CHIP_FACTORY_DATA_ERROR(0x09) +#define CHIP_FACTORY_DATA_PDM_READ_RECORD CHIP_FACTORY_DATA_ERROR(0x0A) +#define CHIP_FACTORY_DATA_RESTORE_MECHANISM CHIP_FACTORY_DATA_ERROR(0x0B) + +// Forward declaration to define the getter for factory data provider impl instance +class FactoryDataProviderImpl; + +/** + * @brief This class provides Commissionable data, Device Attestation Credentials, + * and Device Instance Info. + */ + +class FactoryDataProvider : public DeviceInstanceInfoProvider, + public CommissionableDataProvider, + public Credentials::DeviceAttestationCredentialsProvider +{ +public: + struct Header + { + uint32_t hashId; + uint32_t size; + uint8_t hash[4]; + }; + + // Default factory data IDs + enum FactoryDataId + { + kVerifierId = 1, + kSaltId, + kIcId, + kDacPrivateKeyId, + kDacCertificateId, + kPaiCertificateId, + kDiscriminatorId, + kSetupPasscodeId, + kVidId, + kPidId, + kCertDeclarationId, + kVendorNameId, + kProductNameId, + kSerialNumberId, + kManufacturingDateId, + kHardwareVersionId, + kHardwareVersionStrId, + kUniqueId, + kPartNumber, + kProductURL, + kProductLabel, + kProductFinish, + kProductPrimaryColor, + kMaxId + }; + + static uint32_t kFactoryDataStart; + static uint32_t kFactoryDataSize; + static uint32_t kFactoryDataPayloadStart; + static constexpr uint32_t kLengthOffset = 1; + static constexpr uint32_t kValueOffset = 3; + static constexpr uint32_t kHashLen = 4; + static constexpr size_t kHashId = 0xCE47BA5E; + + virtual ~FactoryDataProvider(); + + virtual CHIP_ERROR Init() = 0; + virtual CHIP_ERROR SignWithDacKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer) = 0; + CHIP_ERROR Validate(); + + CHIP_ERROR SearchForId(uint8_t searchedType, uint8_t * pBuf, size_t bufLength, uint16_t & length, uint32_t * offset = nullptr); + + // ===== Members functions that implement the CommissionableDataProvider + CHIP_ERROR GetSetupDiscriminator(uint16_t & setupDiscriminator) override; + CHIP_ERROR SetSetupDiscriminator(uint16_t setupDiscriminator) override; + CHIP_ERROR GetSpake2pIterationCount(uint32_t & iterationCount) override; + CHIP_ERROR GetSpake2pSalt(MutableByteSpan & saltBuf) override; + CHIP_ERROR GetSpake2pVerifier(MutableByteSpan & verifierBuf, size_t & verifierLen) override; + CHIP_ERROR GetSetupPasscode(uint32_t & setupPasscode) override; + CHIP_ERROR SetSetupPasscode(uint32_t setupPasscode) override; + + // ===== Members functions that implement the DeviceAttestationCredentialsProvider + CHIP_ERROR GetCertificationDeclaration(MutableByteSpan & outBuffer) override; + CHIP_ERROR GetFirmwareInformation(MutableByteSpan & out_firmware_info_buffer) override; + CHIP_ERROR GetDeviceAttestationCert(MutableByteSpan & outBuffer) override; + CHIP_ERROR GetProductAttestationIntermediateCert(MutableByteSpan & outBuffer) override; + CHIP_ERROR SignWithDeviceAttestationKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer) override; + + // ===== Members functions that implement the GenericDeviceInstanceInfoProvider + CHIP_ERROR GetVendorName(char * buf, size_t bufSize) override; + CHIP_ERROR GetVendorId(uint16_t & vendorId) override; + CHIP_ERROR GetProductName(char * buf, size_t bufSize) override; + CHIP_ERROR GetProductId(uint16_t & productId) override; + CHIP_ERROR GetPartNumber(char * buf, size_t bufSize) override; + CHIP_ERROR GetProductURL(char * buf, size_t bufSize) override; + CHIP_ERROR GetProductLabel(char * buf, size_t bufSize) override; + CHIP_ERROR GetHardwareVersionString(char * buf, size_t bufSize) override; + CHIP_ERROR GetSerialNumber(char * buf, size_t bufSize) override; + CHIP_ERROR GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) override; + CHIP_ERROR GetHardwareVersion(uint16_t & hardwareVersion) override; + CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) override; + CHIP_ERROR GetProductFinish(app::Clusters::BasicInformation::ProductFinishEnum * finish) override; + CHIP_ERROR GetProductPrimaryColor(app::Clusters::BasicInformation::ColorEnum * primaryColor) override; + +protected: + Header mHeader; +}; + +extern FactoryDataProvider & FactoryDataPrvd(); + +extern FactoryDataProviderImpl & FactoryDataPrvdImpl(); + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/nxp/k32w/k32w0/FactoryDataProviderImpl.cpp b/src/platform/nxp/k32w0/FactoryDataProviderImpl.cpp similarity index 94% rename from src/platform/nxp/k32w/k32w0/FactoryDataProviderImpl.cpp rename to src/platform/nxp/k32w0/FactoryDataProviderImpl.cpp index dc6acd3b619272..93c09adf5c749d 100644 --- a/src/platform/nxp/k32w/k32w0/FactoryDataProviderImpl.cpp +++ b/src/platform/nxp/k32w0/FactoryDataProviderImpl.cpp @@ -17,9 +17,9 @@ #include #include -#include +#include -#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR extern "C" { #include "Flash_Adapter.h" } @@ -31,7 +31,7 @@ namespace DeviceLayer { FactoryDataProviderImpl::FactoryDataProviderImpl() { -#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR RegisterRestoreMechanism(FactoryDataDefaultRestoreMechanism); #endif } @@ -40,7 +40,7 @@ CHIP_ERROR FactoryDataProviderImpl::Init() { CHIP_ERROR error = CHIP_NO_ERROR; -#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR error = ValidateWithRestore(); #else error = Validate(); @@ -91,7 +91,7 @@ CHIP_ERROR FactoryDataProviderImpl::SignWithDacKey(const ByteSpan & messageToSig return error; } -#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR extern "C" WEAK CHIP_ERROR FactoryDataDefaultRestoreMechanism() { CHIP_ERROR error = CHIP_NO_ERROR; @@ -170,7 +170,7 @@ void FactoryDataProviderImpl::RegisterRestoreMechanism(RestoreMechanism restore) { mRestoreMechanisms.insert(mRestoreMechanisms.end(), restore); } -#endif // CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#endif // CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/nxp/k32w/k32w0/FactoryDataProviderImpl.h b/src/platform/nxp/k32w0/FactoryDataProviderImpl.h similarity index 88% rename from src/platform/nxp/k32w/k32w0/FactoryDataProviderImpl.h rename to src/platform/nxp/k32w0/FactoryDataProviderImpl.h index b359a6d3f196cd..afeb802352bc7b 100644 --- a/src/platform/nxp/k32w/k32w0/FactoryDataProviderImpl.h +++ b/src/platform/nxp/k32w0/FactoryDataProviderImpl.h @@ -16,7 +16,7 @@ */ #pragma once -#include +#include #include namespace chip { @@ -24,7 +24,7 @@ namespace DeviceLayer { /** * This class provides K32W0 specific factory data features. - * CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR - enables factory data OTA + * CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR - enables factory data OTA */ class FactoryDataProviderImpl : public FactoryDataProvider @@ -35,7 +35,7 @@ class FactoryDataProviderImpl : public FactoryDataProvider CHIP_ERROR Init() override; CHIP_ERROR SignWithDacKey(const ByteSpan & messageToSign, MutableByteSpan & outSignBuffer) override; -#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR using RestoreMechanism = CHIP_ERROR (*)(void); static CHIP_ERROR UpdateData(uint8_t * pBuf); diff --git a/src/platform/nxp/k32w/k32w0/InetPlatformConfig.h b/src/platform/nxp/k32w0/InetPlatformConfig.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/InetPlatformConfig.h rename to src/platform/nxp/k32w0/InetPlatformConfig.h diff --git a/src/platform/nxp/k32w/k32w0/K32W0Config.cpp b/src/platform/nxp/k32w0/K32W0Config.cpp similarity index 99% rename from src/platform/nxp/k32w/k32w0/K32W0Config.cpp rename to src/platform/nxp/k32w0/K32W0Config.cpp index 850a1b7398ef06..2054ef5da619bf 100644 --- a/src/platform/nxp/k32w/k32w0/K32W0Config.cpp +++ b/src/platform/nxp/k32w0/K32W0Config.cpp @@ -25,7 +25,7 @@ /* this file behaves like a config.h, comes first */ #include -#include +#include #include #include diff --git a/src/platform/nxp/k32w/k32w0/K32W0Config.h b/src/platform/nxp/k32w0/K32W0Config.h similarity index 98% rename from src/platform/nxp/k32w/k32w0/K32W0Config.h rename to src/platform/nxp/k32w0/K32W0Config.h index e364c045c25b1c..7080e62e747bf1 100644 --- a/src/platform/nxp/k32w/k32w0/K32W0Config.h +++ b/src/platform/nxp/k32w0/K32W0Config.h @@ -20,7 +20,7 @@ #include #include -#include +#include namespace chip { namespace DeviceLayer { diff --git a/src/platform/nxp/k32w/k32w0/KeyValueStoreManagerImpl.cpp b/src/platform/nxp/k32w0/KeyValueStoreManagerImpl.cpp similarity index 93% rename from src/platform/nxp/k32w/k32w0/KeyValueStoreManagerImpl.cpp rename to src/platform/nxp/k32w0/KeyValueStoreManagerImpl.cpp index 8dbf3e5bd71903..50f900583769f7 100644 --- a/src/platform/nxp/k32w/k32w0/KeyValueStoreManagerImpl.cpp +++ b/src/platform/nxp/k32w0/KeyValueStoreManagerImpl.cpp @@ -25,9 +25,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include namespace chip { @@ -41,6 +41,7 @@ Internal::RamStorage KeyValueStoreManagerImpl::sKeysStorage = { kNvmId_K Internal::RamStorage KeyValueStoreManagerImpl::sValuesStorage = { kNvmId_KvsValues, "Values" }; Internal::RamStorage KeyValueStoreManagerImpl::sSubscriptionStorage = { kNvmId_KvsSubscription, "Subscriptions" }; Internal::RamStorage KeyValueStoreManagerImpl::sGroupsStorage = { kNvmId_KvsGroups, "Groups" }; +Internal::RamStorage KeyValueStoreManagerImpl::sAclStorage = { kNvmId_KvsAcl, "Acl" }; KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; @@ -63,6 +64,12 @@ static inline bool IsKeyRelatedToSubscriptions(const char * key) return _key.find("g/su") == 0; } +static inline bool IsKeyRelatedToAcl(const char * key) +{ + std::string _key(key); + return _key.find("/ac/") != std::string::npos; +} + static Internal::RamStorage * GetValStorage(const char * key) { Internal::RamStorage * storage = nullptr; @@ -70,6 +77,7 @@ static Internal::RamStorage * GetValStorage(const char * key) storage = IsKeyRelatedToSubscriptions(key) ? &KeyValueStoreManagerImpl::sSubscriptionStorage : &KeyValueStoreManagerImpl::sValuesStorage; storage = IsKeyRelatedToGroups(key) ? &KeyValueStoreManagerImpl::sGroupsStorage : storage; + storage = IsKeyRelatedToAcl(key) ? &KeyValueStoreManagerImpl::sAclStorage : storage; return storage; } @@ -81,6 +89,7 @@ static Internal::RamStorage * GetKeyStorage(const char * key) storage = IsKeyRelatedToSubscriptions(key) ? &KeyValueStoreManagerImpl::sSubscriptionStorage : &KeyValueStoreManagerImpl::sKeysStorage; storage = IsKeyRelatedToGroups(key) ? &KeyValueStoreManagerImpl::sGroupsStorage : storage; + storage = IsKeyRelatedToAcl(key) ? &KeyValueStoreManagerImpl::sAclStorage : storage; return storage; } @@ -145,6 +154,12 @@ CHIP_ERROR KeyValueStoreManagerImpl::Init() ChipLogProgress(DeviceLayer, "Cannot init KVS groups storage with id: %d. Error: %s", kNvmId_KvsGroups, ErrorStr(err)); } + err = sAclStorage.Init(Internal::RamStorage::kRamBufferInitialSize, true); + if (err != CHIP_NO_ERROR) + { + ChipLogProgress(DeviceLayer, "Cannot init KVS acl storage with id: %d. Error: %s", kNvmId_KvsAcl, ErrorStr(err)); + } + #if CONFIG_CHIP_K32W0_KVS_MOVE_KEYS_TO_SPECIFIC_STORAGE ChipLogProgress(DeviceLayer, "Moving some keys to dedicated storage"); MoveKeysAndValues(); diff --git a/src/platform/nxp/k32w/k32w0/KeyValueStoreManagerImpl.h b/src/platform/nxp/k32w0/KeyValueStoreManagerImpl.h similarity index 95% rename from src/platform/nxp/k32w/k32w0/KeyValueStoreManagerImpl.h rename to src/platform/nxp/k32w0/KeyValueStoreManagerImpl.h index 718b92df6beb39..57d877beaeaaf9 100644 --- a/src/platform/nxp/k32w/k32w0/KeyValueStoreManagerImpl.h +++ b/src/platform/nxp/k32w0/KeyValueStoreManagerImpl.h @@ -24,7 +24,7 @@ #pragma once -#include +#include namespace chip { namespace DeviceLayer { @@ -41,6 +41,8 @@ class KeyValueStoreManagerImpl final : public KeyValueStoreManager static Internal::RamStorage sSubscriptionStorage; /* Storage for KVS groups keys and values. Cleared during factory reset. */ static Internal::RamStorage sGroupsStorage; + /* Storage for KVS ACL keys and values. Cleared during factory reset. */ + static Internal::RamStorage sAclStorage; // Allow the KeyValueStoreManager interface class to delegate method calls to // the implementation methods provided by this class. diff --git a/src/platform/nxp/k32w/k32w0/Logging.cpp b/src/platform/nxp/k32w0/Logging.cpp similarity index 100% rename from src/platform/nxp/k32w/k32w0/Logging.cpp rename to src/platform/nxp/k32w0/Logging.cpp diff --git a/src/platform/nxp/k32w/k32w0/LowPowerHooks.cpp b/src/platform/nxp/k32w0/LowPowerHooks.cpp similarity index 100% rename from src/platform/nxp/k32w/k32w0/LowPowerHooks.cpp rename to src/platform/nxp/k32w0/LowPowerHooks.cpp diff --git a/src/platform/nxp/k32w/k32w0/NFCManagerImpl.cpp b/src/platform/nxp/k32w0/NFCManagerImpl.cpp similarity index 100% rename from src/platform/nxp/k32w/k32w0/NFCManagerImpl.cpp rename to src/platform/nxp/k32w0/NFCManagerImpl.cpp diff --git a/src/platform/nxp/k32w/k32w0/NFCManagerImpl.h b/src/platform/nxp/k32w0/NFCManagerImpl.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/NFCManagerImpl.h rename to src/platform/nxp/k32w0/NFCManagerImpl.h diff --git a/src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.cpp b/src/platform/nxp/k32w0/OTAFactoryDataProcessor.cpp similarity index 97% rename from src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.cpp rename to src/platform/nxp/k32w0/OTAFactoryDataProcessor.cpp index d40d2ae3c17f5a..b6777c7dc32820 100644 --- a/src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.cpp +++ b/src/platform/nxp/k32w0/OTAFactoryDataProcessor.cpp @@ -18,9 +18,10 @@ #include #include -#include -#include -#include +#include +#include +#include +#include #include "PDM.h" #include "fsl_flash.h" diff --git a/src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.h b/src/platform/nxp/k32w0/OTAFactoryDataProcessor.h similarity index 93% rename from src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.h rename to src/platform/nxp/k32w0/OTAFactoryDataProcessor.h index 8682d0bcc1e9dc..3109e64a8d0ae3 100644 --- a/src/platform/nxp/k32w/k32w0/OTAFactoryDataProcessor.h +++ b/src/platform/nxp/k32w0/OTAFactoryDataProcessor.h @@ -21,9 +21,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include namespace chip { diff --git a/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.cpp b/src/platform/nxp/k32w0/OTAFirmwareProcessor.cpp similarity index 96% rename from src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.cpp rename to src/platform/nxp/k32w0/OTAFirmwareProcessor.cpp index f63aa745378851..c7a1a2bbf435dd 100644 --- a/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.cpp +++ b/src/platform/nxp/k32w0/OTAFirmwareProcessor.cpp @@ -17,9 +17,9 @@ */ #include -#include -#include -#include +#include +#include +#include #include "OtaSupport.h" #include "OtaUtils.h" diff --git a/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.h b/src/platform/nxp/k32w0/OTAFirmwareProcessor.h similarity index 96% rename from src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.h rename to src/platform/nxp/k32w0/OTAFirmwareProcessor.h index 5a1092ef5fbc46..444243f0c885d0 100644 --- a/src/platform/nxp/k32w/k32w0/OTAFirmwareProcessor.h +++ b/src/platform/nxp/k32w0/OTAFirmwareProcessor.h @@ -19,7 +19,7 @@ #pragma once #include -#include +#include namespace chip { diff --git a/src/platform/nxp/k32w/k32w0/OTAHooks.cpp b/src/platform/nxp/k32w0/OTAHooks.cpp similarity index 87% rename from src/platform/nxp/k32w/k32w0/OTAHooks.cpp rename to src/platform/nxp/k32w0/OTAHooks.cpp index a00ae428a0f40d..30df88177ffdc6 100644 --- a/src/platform/nxp/k32w/k32w0/OTAHooks.cpp +++ b/src/platform/nxp/k32w0/OTAHooks.cpp @@ -16,16 +16,16 @@ * limitations under the License. */ -#include +#include #include #include -#include -#include -#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR -#include -#endif // CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#include +#include +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR +#include +#endif // CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR #include "OtaSupport.h" @@ -51,9 +51,9 @@ extern "C" WEAK CHIP_ERROR OtaHookInit() { static chip::OTAFirmwareProcessor sApplicationProcessor; static chip::OTAFirmwareProcessor sBootloaderProcessor; -#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR static chip::OTAFactoryDataProcessor sFactoryDataProcessor; -#endif // CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#endif // CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR #if CONFIG_CHIP_K32W0_MAX_ENTRIES_TEST static chip::OTAFirmwareProcessor processors[8]; #endif @@ -64,9 +64,9 @@ extern "C" WEAK CHIP_ERROR OtaHookInit() auto & imageProcessor = chip::OTAImageProcessorImpl::GetDefaultInstance(); ReturnErrorOnFailure(imageProcessor.RegisterProcessor(1, &sApplicationProcessor)); ReturnErrorOnFailure(imageProcessor.RegisterProcessor(2, &sBootloaderProcessor)); -#if CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#if CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR ReturnErrorOnFailure(imageProcessor.RegisterProcessor(3, &sFactoryDataProcessor)); -#endif // CONFIG_CHIP_K32W0_OTA_FACTORY_DATA_PROCESSOR +#endif // CONFIG_CHIP_OTA_FACTORY_DATA_PROCESSOR #if CONFIG_CHIP_K32W0_MAX_ENTRIES_TEST for (auto i = 0; i < 8; i++) { diff --git a/src/platform/nxp/k32w/k32w0/PlatformManagerImpl.cpp b/src/platform/nxp/k32w0/PlatformManagerImpl.cpp similarity index 98% rename from src/platform/nxp/k32w/k32w0/PlatformManagerImpl.cpp rename to src/platform/nxp/k32w0/PlatformManagerImpl.cpp index 198f9318ba41fb..1a98552cb7e0d9 100644 --- a/src/platform/nxp/k32w/k32w0/PlatformManagerImpl.cpp +++ b/src/platform/nxp/k32w0/PlatformManagerImpl.cpp @@ -29,8 +29,8 @@ #include #include #include -#include -#include +#include +#include #if CHIP_SYSTEM_CONFIG_USE_LWIP #include diff --git a/src/platform/nxp/k32w/k32w0/PlatformManagerImpl.h b/src/platform/nxp/k32w0/PlatformManagerImpl.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/PlatformManagerImpl.h rename to src/platform/nxp/k32w0/PlatformManagerImpl.h diff --git a/src/platform/nxp/k32w/k32w0/RamStorage.cpp b/src/platform/nxp/k32w0/RamStorage.cpp similarity index 99% rename from src/platform/nxp/k32w/k32w0/RamStorage.cpp rename to src/platform/nxp/k32w0/RamStorage.cpp index ea32a7f9c525c8..a478a582b98fb1 100644 --- a/src/platform/nxp/k32w/k32w0/RamStorage.cpp +++ b/src/platform/nxp/k32w0/RamStorage.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include "pdm_ram_storage_glue.h" diff --git a/src/platform/nxp/k32w/k32w0/RamStorage.h b/src/platform/nxp/k32w0/RamStorage.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/RamStorage.h rename to src/platform/nxp/k32w0/RamStorage.h diff --git a/src/platform/nxp/k32w/k32w0/SystemPlatformConfig.h b/src/platform/nxp/k32w0/SystemPlatformConfig.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/SystemPlatformConfig.h rename to src/platform/nxp/k32w0/SystemPlatformConfig.h diff --git a/src/platform/nxp/k32w/k32w0/SystemTimeSupport.cpp b/src/platform/nxp/k32w0/SystemTimeSupport.cpp similarity index 100% rename from src/platform/nxp/k32w/k32w0/SystemTimeSupport.cpp rename to src/platform/nxp/k32w0/SystemTimeSupport.cpp diff --git a/src/platform/nxp/k32w/k32w0/ThreadStackManagerImpl.cpp b/src/platform/nxp/k32w0/ThreadStackManagerImpl.cpp similarity index 100% rename from src/platform/nxp/k32w/k32w0/ThreadStackManagerImpl.cpp rename to src/platform/nxp/k32w0/ThreadStackManagerImpl.cpp diff --git a/src/platform/nxp/k32w/k32w0/ThreadStackManagerImpl.h b/src/platform/nxp/k32w0/ThreadStackManagerImpl.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/ThreadStackManagerImpl.h rename to src/platform/nxp/k32w0/ThreadStackManagerImpl.h diff --git a/src/platform/nxp/k32w/k32w0/args.gni b/src/platform/nxp/k32w0/args.gni similarity index 89% rename from src/platform/nxp/k32w/k32w0/args.gni rename to src/platform/nxp/k32w0/args.gni index 5f90c8248e207a..1076eea4f4cf7f 100644 --- a/src/platform/nxp/k32w/k32w0/args.gni +++ b/src/platform/nxp/k32w0/args.gni @@ -16,15 +16,14 @@ import("//build_overrides/chip.gni") import("//build_overrides/nxp_sdk.gni") import("//build_overrides/openthread.gni") -nxp_platform = "k32w/k32w0" +nxp_platform = "k32w0" nxp_sdk_name = "k32w0_sdk" nxp_device_layer = "nxp/${nxp_platform}" nxp_use_lwip = false nxp_use_mbedtls_port = false if (getenv("NXP_K32W0_SDK_ROOT") == "") { - k32w0_sdk_root = - "${nxp_sdk_matter_support_root}/github_sdk/k32w0_sdk/repo/core" + k32w0_sdk_root = "${nxp_sdk_matter_support_root}/github_sdk/k32w0/repo" } else { k32w0_sdk_root = getenv("NXP_K32W0_SDK_ROOT") } @@ -72,6 +71,6 @@ openthread_external_mbedtls = mbedtls_target openthread_project_core_config_file = "OpenThreadConfig.h" openthread_core_config_platform_check_file = "openthread-core-k32w061-config-check.h" -openthread_core_config_deps = [ "${chip_root}/examples/platform/nxp/k32w/k32w0:openthread_core_config_k32w0_chip_examples" ] +openthread_core_config_deps = [ "${nxp_sdk_matter_support_root}/examples/platform/k32w0:openthread_core_config_k32w0_chip_examples" ] -openthread_external_platform = "${chip_root}/third_party/openthread/platforms/nxp/k32w/k32w0:libopenthread-k32w0" +openthread_external_platform = "${chip_root}/third_party/openthread/platforms/nxp/k32w0:libopenthread-k32w0" diff --git a/src/platform/nxp/k32w/k32w0/ble_function_mux.c b/src/platform/nxp/k32w0/ble_function_mux.c similarity index 100% rename from src/platform/nxp/k32w/k32w0/ble_function_mux.c rename to src/platform/nxp/k32w0/ble_function_mux.c diff --git a/src/platform/nxp/k32w/k32w0/ble_function_mux.h b/src/platform/nxp/k32w0/ble_function_mux.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/ble_function_mux.h rename to src/platform/nxp/k32w0/ble_function_mux.h diff --git a/src/platform/nxp/k32w/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp b/src/platform/nxp/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp similarity index 100% rename from src/platform/nxp/k32w/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp rename to src/platform/nxp/k32w0/crypto/CHIPCryptoPALNXPUltrafastP256.cpp diff --git a/src/platform/nxp/k32w/k32w0/gatt_db.h b/src/platform/nxp/k32w0/gatt_db.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/gatt_db.h rename to src/platform/nxp/k32w0/gatt_db.h diff --git a/src/platform/nxp/k32w/k32w0/gatt_uuid128.h b/src/platform/nxp/k32w0/gatt_uuid128.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/gatt_uuid128.h rename to src/platform/nxp/k32w0/gatt_uuid128.h diff --git a/src/platform/nxp/k32w/k32w0/k32w0-chip-mbedtls-config.h b/src/platform/nxp/k32w0/k32w0-chip-mbedtls-config.h similarity index 100% rename from src/platform/nxp/k32w/k32w0/k32w0-chip-mbedtls-config.h rename to src/platform/nxp/k32w0/k32w0-chip-mbedtls-config.h diff --git a/third_party/nxp/nxp_matter_support b/third_party/nxp/nxp_matter_support index ac504a0cc38963..e6deaf56001387 160000 --- a/third_party/nxp/nxp_matter_support +++ b/third_party/nxp/nxp_matter_support @@ -1 +1 @@ -Subproject commit ac504a0cc389632c0e26b4f04e65914d3a9ba8bd +Subproject commit e6deaf5600138763ea68418e34bc62a02d1aef0d diff --git a/third_party/openthread/platforms/nxp/k32w/k32w0/BUILD.gn b/third_party/openthread/platforms/nxp/k32w0/BUILD.gn similarity index 92% rename from third_party/openthread/platforms/nxp/k32w/k32w0/BUILD.gn rename to third_party/openthread/platforms/nxp/k32w0/BUILD.gn index 7ebd860e571371..bf9ed42e894965 100644 --- a/third_party/openthread/platforms/nxp/k32w/k32w0/BUILD.gn +++ b/third_party/openthread/platforms/nxp/k32w0/BUILD.gn @@ -30,7 +30,7 @@ config("openthread_k32w0_config") { "${openthread_nxp_root}/src/k32w0/platform", "${openthread_nxp_root}/src/common", ] - include_dirs += [ "${chip_root}/examples/platform/nxp/k32w/k32w0" ] + include_dirs += [ "${nxp_sdk_matter_support_root}/examples/platform/k32w0" ] if (is_clang) { cflags = [ "-Wno-format-nonliteral" ] @@ -46,7 +46,7 @@ config("openthread_k32w0_config") { source_set("openthread_core_config_k32w0") { sources = [ - "${chip_root}/examples/platform/nxp/k32w/k32w0/app/project_include/OpenThreadConfig.h", + "${nxp_sdk_matter_support_root}/examples/platform/k32w0/app/project_include/OpenThreadConfig.h", "${openthread_nxp_root}/src/k32w0/k32w061/openthread-core-k32w061-config-check.h", ] @@ -95,7 +95,7 @@ source_set("libopenthread-k32w0") { "${nxp_sdk_build_root}:nxp_sdk", "${nxp_sdk_build_root}/${nxp_sdk_name}:mbedtls", "${openthread_root}/src/core:libopenthread_core_headers", - "../../..:libopenthread-platform", - "../../..:libopenthread-platform-utils", + "../..:libopenthread-platform", + "../..:libopenthread-platform-utils", ] } From d619f75ecbe7d53b049afbc685439141282e0544 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Tue, 6 Aug 2024 18:39:57 -0400 Subject: [PATCH 25/41] fabric-bridge-app: Prevent crash when reading CADMIN cluster on bridge node (#34790) * Prevent crash when reading CADMIN cluster on dynamic bridge node endpoints * Restyled by clang-format --------- Co-authored-by: Restyled.io --- .../fabric-bridge-common/src/ZCLCallbacks.cpp | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp index 9a0467be4e27e8..26e727901abf0e 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp +++ b/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp @@ -26,6 +26,7 @@ using namespace ::chip; using namespace ::chip::app::Clusters; #define ZCL_DESCRIPTOR_CLUSTER_REVISION (1u) +#define ZCL_ADMINISTRATOR_COMMISSIONING_CLUSTER_REVISION (1u) #define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION (2u) #define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP (0u) @@ -37,9 +38,14 @@ Protocols::InteractionModel::Status emberAfExternalAttributeReadCallback(Endpoin AttributeId attributeId = attributeMetadata->attributeId; BridgedDevice * dev = BridgeDeviceMgr().GetDevice(endpoint); - if (dev != nullptr && clusterId == app::Clusters::BridgedDeviceBasicInformation::Id) + if (dev == nullptr) { - using namespace app::Clusters::BridgedDeviceBasicInformation::Attributes; + return Protocols::InteractionModel::Status::Failure; + } + + if (clusterId == BridgedDeviceBasicInformation::Id) + { + using namespace BridgedDeviceBasicInformation::Attributes; ChipLogProgress(NotSpecified, "HandleReadBridgedDeviceBasicAttribute: attrId=%d, maxReadLength=%d", attributeId, maxReadLength); @@ -69,6 +75,21 @@ Protocols::InteractionModel::Status emberAfExternalAttributeReadCallback(Endpoin return Protocols::InteractionModel::Status::Success; } + if (clusterId == AdministratorCommissioning::Id) + { + // TODO(#34791) This is a workaround to prevent crash. CADMIN is still reading incorrect + // Attribute values on dynamic endpoint as it only reads the root node and not the actual bridge + // device we are representing here, when addressing the issue over there we can more easily + // resolve this workaround. + if ((attributeId == AdministratorCommissioning::Attributes::ClusterRevision::Id) && (maxReadLength == 2)) + { + uint16_t rev = ZCL_ADMINISTRATOR_COMMISSIONING_CLUSTER_REVISION; + memcpy(buffer, &rev, sizeof(rev)); + return Protocols::InteractionModel::Status::Success; + } + return Protocols::InteractionModel::Status::Failure; + } + return Protocols::InteractionModel::Status::Failure; } From 62255da130785c9dc501a70a47d3e7743ee9d885 Mon Sep 17 00:00:00 2001 From: Lazar Kovacic Date: Wed, 7 Aug 2024 01:06:43 +0200 Subject: [PATCH 26/41] Fix not sending CDC message when passcode is cancelled on TV app (#34507) * Fix not sending CDC message when passcode is cancelled * Update logic * Restyled by whitespace * Restyled by clang-format * Update code --------- Co-authored-by: Restyled.io --- .../CommissionerDiscoveryController.cpp | 28 +++++++++++++++++-- .../UserDirectedCommissioning.h | 10 ++++++- .../UserDirectedCommissioningClient.cpp | 3 ++ .../UserDirectedCommissioningServer.cpp | 2 ++ 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/controller/CommissionerDiscoveryController.cpp b/src/controller/CommissionerDiscoveryController.cpp index 7f13a4323d2f5c..09a22e03e0bcd2 100644 --- a/src/controller/CommissionerDiscoveryController.cpp +++ b/src/controller/CommissionerDiscoveryController.cpp @@ -589,12 +589,36 @@ void CommissionerDiscoveryController::Cancel() return; } UDCClientState * client = mUdcServer->GetUDCClients().FindUDCClientState(mCurrentInstance); - if (client == nullptr || client->GetUDCClientProcessingState() != UDCClientProcessingState::kPromptingUser) + + if (client == nullptr) + { + ChipLogError(AppServer, "UX Cancel: client not found"); + return; + } + + auto state = client->GetUDCClientProcessingState(); + + bool isCancelableState = + (state == UDCClientProcessingState::kPromptingUser || state == UDCClientProcessingState::kObtainingOnboardingPayload || + state == UDCClientProcessingState::kWaitingForCommissionerPasscodeReady); + + if (!isCancelableState) { - ChipLogError(AppServer, "UX Cancel: invalid state for cancel"); + ChipLogError(AppServer, "UX Cancel: invalid state for cancel, state: %hhu", static_cast(state)); return; } + client->SetUDCClientProcessingState(UDCClientProcessingState::kUserDeclined); + + if (state == UDCClientProcessingState::kObtainingOnboardingPayload || + state == UDCClientProcessingState::kWaitingForCommissionerPasscodeReady) + { + ChipLogDetail(AppServer, "UX Cancel: user cancelled entering PIN code, sending CDC"); + CommissionerDeclaration cd; + cd.SetCancelPasscode(true); + mUdcServer->SendCDCMessage(cd, Transport::PeerAddress::UDP(client->GetPeerAddress().GetIPAddress(), client->GetCdPort())); + } + mPendingConsent = false; ResetState(); } diff --git a/src/protocols/user_directed_commissioning/UserDirectedCommissioning.h b/src/protocols/user_directed_commissioning/UserDirectedCommissioning.h index cf9a55365b9191..fb1aedc03e8d6e 100644 --- a/src/protocols/user_directed_commissioning/UserDirectedCommissioning.h +++ b/src/protocols/user_directed_commissioning/UserDirectedCommissioning.h @@ -227,7 +227,6 @@ class DLL_EXPORT IdentificationDeclaration { ChipLogDetail(AppServer, "\tpairing hint: %d", mPairingHint); } - if (mNoPasscode) { ChipLogDetail(AppServer, "\tno passcode: true"); @@ -349,6 +348,9 @@ class DLL_EXPORT CommissionerDeclaration void SetQRCodeDisplayed(bool newValue) { mQRCodeDisplayed = newValue; }; bool GetQRCodeDisplayed() const { return mQRCodeDisplayed; }; + void SetCancelPasscode(bool newValue) { mCancelPasscode = newValue; }; + bool GetCancelPasscode() const { return mCancelPasscode; }; + /** * Writes the CommissionerDeclaration message to the given buffer. * @@ -390,6 +392,10 @@ class DLL_EXPORT CommissionerDeclaration { ChipLogDetail(AppServer, "\tQR code displayed: true"); } + if (mCancelPasscode) + { + ChipLogDetail(AppServer, "\tPasscode cancelled: true"); + } ChipLogDetail(AppServer, "---- Commissioner Declaration End ----"); } @@ -403,6 +409,7 @@ class DLL_EXPORT CommissionerDeclaration kPasscodeDialogDisplayedTag, kCommissionerPasscodeTag, kQRCodeDisplayedTag, + kCancelPasscodeTag, kMaxNum = UINT8_MAX }; @@ -413,6 +420,7 @@ class DLL_EXPORT CommissionerDeclaration bool mPasscodeDialogDisplayed = false; bool mCommissionerPasscode = false; bool mQRCodeDisplayed = false; + bool mCancelPasscode = false; }; class DLL_EXPORT InstanceNameResolver diff --git a/src/protocols/user_directed_commissioning/UserDirectedCommissioningClient.cpp b/src/protocols/user_directed_commissioning/UserDirectedCommissioningClient.cpp index aeb5691be2554c..f0ee3bbe69abfd 100644 --- a/src/protocols/user_directed_commissioning/UserDirectedCommissioningClient.cpp +++ b/src/protocols/user_directed_commissioning/UserDirectedCommissioningClient.cpp @@ -223,6 +223,9 @@ CHIP_ERROR CommissionerDeclaration::ReadPayload(uint8_t * udcPayload, size_t pay case kQRCodeDisplayedTag: err = reader.Get(mQRCodeDisplayed); break; + case kCancelPasscodeTag: + err = reader.Get(mCancelPasscode); + break; } } diff --git a/src/protocols/user_directed_commissioning/UserDirectedCommissioningServer.cpp b/src/protocols/user_directed_commissioning/UserDirectedCommissioningServer.cpp index fb31049d1d99a9..118ba7c7c524e4 100644 --- a/src/protocols/user_directed_commissioning/UserDirectedCommissioningServer.cpp +++ b/src/protocols/user_directed_commissioning/UserDirectedCommissioningServer.cpp @@ -435,6 +435,8 @@ uint32_t CommissionerDeclaration::WritePayload(uint8_t * payloadBuffer, size_t p LogErrorOnFailure(err)); VerifyOrExit(CHIP_NO_ERROR == (err = writer.PutBoolean(chip::TLV::ContextTag(kQRCodeDisplayedTag), mQRCodeDisplayed)), LogErrorOnFailure(err)); + VerifyOrExit(CHIP_NO_ERROR == (err = writer.PutBoolean(chip::TLV::ContextTag(kCancelPasscodeTag), mCancelPasscode)), + LogErrorOnFailure(err)); VerifyOrExit(CHIP_NO_ERROR == (err = writer.EndContainer(outerContainerType)), LogErrorOnFailure(err)); VerifyOrExit(CHIP_NO_ERROR == (err = writer.Finalize()), LogErrorOnFailure(err)); From 212d6abf7be4e406447d6039efb22bdd2f9c619d Mon Sep 17 00:00:00 2001 From: Jeff Tung <100387939+jtung-apple@users.noreply.github.com> Date: Tue, 6 Aug 2024 17:39:44 -0700 Subject: [PATCH 27/41] [Darwin] MTRDevice subscription estalished handler should change state before async (#34797) * [Darwin] MTRDevice subscription estalished handler should change state before async * Update src/darwin/Framework/CHIP/MTRDevice.mm Co-authored-by: Kiel Oleson * Addressed PR review - moved code comment to correct place --------- Co-authored-by: Kiel Oleson --- src/darwin/Framework/CHIP/MTRDevice.mm | 33 +++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/darwin/Framework/CHIP/MTRDevice.mm b/src/darwin/Framework/CHIP/MTRDevice.mm index b8ef8694825e1f..07b695cd3c80d4 100644 --- a/src/darwin/Framework/CHIP/MTRDevice.mm +++ b/src/darwin/Framework/CHIP/MTRDevice.mm @@ -1193,23 +1193,21 @@ - (void)_handleSubscriptionEstablished { os_unfair_lock_lock(&self->_lock); - // We have completed the subscription work - remove from the subscription pool. - [self _clearSubscriptionPoolWork]; - - // reset subscription attempt wait time when subscription succeeds - _lastSubscriptionAttemptWait = 0; - if (HadSubscriptionEstablishedOnce(_internalDeviceState)) { - [self _changeInternalState:MTRInternalDeviceStateLaterSubscriptionEstablished]; - } else { - MATTER_LOG_METRIC_END(kMetricMTRDeviceInitialSubscriptionSetup, CHIP_NO_ERROR); - [self _changeInternalState:MTRInternalDeviceStateInitialSubscriptionEstablished]; + // If subscription had reset since this handler was scheduled, do not execute "established" logic below + if (!HaveSubscriptionEstablishedRightNow(_internalDeviceState)) { + MTR_LOG("%@ _handleSubscriptionEstablished run with internal state %lu - skipping subscription establishment logic", self, static_cast(_internalDeviceState)); + return; } - [self _changeState:MTRDeviceStateReachable]; + // We have completed the subscription work - remove from the subscription pool. + [self _clearSubscriptionPoolWork]; // No need to monitor connectivity after subscription establishment [self _stopConnectivityMonitoring]; + // reset subscription attempt wait time when subscription succeeds + _lastSubscriptionAttemptWait = 0; + auto initialSubscribeStart = _initialSubscribeStart; // We no longer need to track subscribe latency for this device. _initialSubscribeStart = nil; @@ -2476,6 +2474,19 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason }, ^(void) { MTR_LOG("%@ got subscription established", self); + std::lock_guard lock(self->_lock); + + // First synchronously change state + if (HadSubscriptionEstablishedOnce(self->_internalDeviceState)) { + [self _changeInternalState:MTRInternalDeviceStateLaterSubscriptionEstablished]; + } else { + MATTER_LOG_METRIC_END(kMetricMTRDeviceInitialSubscriptionSetup, CHIP_NO_ERROR); + [self _changeInternalState:MTRInternalDeviceStateInitialSubscriptionEstablished]; + } + + [self _changeState:MTRDeviceStateReachable]; + + // Then async work that shouldn't be performed on the matter queue dispatch_async(self.queue, ^{ // OnSubscriptionEstablished [self _handleSubscriptionEstablished]; From 82579f17319e212328b0a6ed9950a308ad0d0d0d Mon Sep 17 00:00:00 2001 From: Kiel Oleson Date: Tue, 6 Aug 2024 18:56:35 -0700 Subject: [PATCH 28/41] [Darwin] MTRDevice -> MTRDevice_Concrete (#34813) * step 1: duplicate MTRDevice start closing off `MTRDevice` direct use add a note to self / reviewers fix `newBaseDevice` / `removeExpectedValue[s]` error ty @bzbarsky-apple move `MTRDevice_Concrete.h` to Project scope was Public note to self about coming change in MTRDeviceController move some MTRDevice utilities to MTRDevice_Internal.h where they are at least shared between MTRDevice and MTRDevice_Concrete. but probably they merit their own files - the header is getting heavy add subclass-facing init to `MTRDevice` superclass for `MTRDevice_Concrete` code was `NSObject`, but now is `MTRDevice`, which hides its `init`s. fix build of `MTRDevice_Internal.h` Revert "move some MTRDevice utilities" This reverts commit ba7331fd032d7096645b21d4d6564df150da126f. fix MTRDevice_Concrete block-scoped pointer types move clamped number to utilities remove duplicated MTRClampedNumber implementations more `MTRClampedNumber` cleanup duplicate MTRDeviceDelegateInfo for now restore prematurely removed `MTRDevice` methods move common `MTRDeviceClusterData` keys remove now-obsolete include for CodeUtils remove duplicate `MTRDeviceClusterData` remove duplicate key symbols from `MTRDevice_Concrete` remove availability annotations for nonpublic API Restyled by whitespace Restyled by clang-format remove superfluous init/new signatures available by default * remove now-obvious comment * start using `MTRDevice_Concrete` when vending from `MTRDeviceController` * Restyled by clang-format * Update src/darwin/Framework/CHIP/MTRDevice_Concrete.h Co-authored-by: Boris Zbarsky * Restyled by clang-format --------- Co-authored-by: Restyled.io Co-authored-by: Justin Wood Co-authored-by: Boris Zbarsky --- src/darwin/Framework/CHIP/MTRDevice.mm | 23 +- .../Framework/CHIP/MTRDeviceController.mm | 3 +- .../Framework/CHIP/MTRDevice_Concrete.h | 27 + .../Framework/CHIP/MTRDevice_Concrete.mm | 4220 +++++++++++++++++ .../Framework/CHIP/MTRDevice_Internal.h | 11 +- src/darwin/Framework/CHIP/MTRUtilities.h | 2 + src/darwin/Framework/CHIP/MTRUtilities.mm | 10 + .../Matter.xcodeproj/project.pbxproj | 8 + 8 files changed, 4284 insertions(+), 20 deletions(-) create mode 100644 src/darwin/Framework/CHIP/MTRDevice_Concrete.h create mode 100644 src/darwin/Framework/CHIP/MTRDevice_Concrete.mm diff --git a/src/darwin/Framework/CHIP/MTRDevice.mm b/src/darwin/Framework/CHIP/MTRDevice.mm index 07b695cd3c80d4..9ce2e3d4026f68 100644 --- a/src/darwin/Framework/CHIP/MTRDevice.mm +++ b/src/darwin/Framework/CHIP/MTRDevice.mm @@ -142,16 +142,6 @@ - (BOOL)callDelegateSynchronouslyWithBlock:(void (^)(id))bloc #endif @end -NSNumber * MTRClampedNumber(NSNumber * aNumber, NSNumber * min, NSNumber * max) -{ - if ([aNumber compare:min] == NSOrderedAscending) { - return min; - } else if ([aNumber compare:max] == NSOrderedDescending) { - return max; - } - return aNumber; -} - /* BEGIN DRAGONS: Note methods here cannot be renamed, and are used by private callers, do not rename, remove or modify behavior here */ @interface NSObject (MatterPrivateForInternalDragonsDoNotFeed) @@ -252,10 +242,6 @@ @implementation MTRDeviceClusterData { NSMutableDictionary * _attributes; } -static NSString * const sDataVersionKey = @"dataVersion"; -static NSString * const sAttributesKey = @"attributes"; -static NSString * const sLastInitialSubscribeLatencyKey = @"lastInitialSubscribeLatency"; - - (void)storeValue:(MTRDeviceDataValueDictionary _Nullable)value forAttribute:(NSNumber *)attribute { _attributes[attribute] = value; @@ -498,6 +484,15 @@ @implementation MTRDevice { NSMutableSet * _delegates; } +- (instancetype)initForSubclasses +{ + if (self = [super init]) { + // nothing, as superclass of MTRDevice is NSObject + } + + return self; +} + - (instancetype)initWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller { if (self = [super init]) { diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index 2e4bb6d4fb0400..6c312d510a93a7 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -31,6 +31,7 @@ #import "MTRDeviceControllerLocalTestStorage.h" #import "MTRDeviceControllerStartupParams.h" #import "MTRDeviceControllerStartupParams_Internal.h" +#import "MTRDevice_Concrete.h" #import "MTRDevice_Internal.h" #import "MTRError_Internal.h" #import "MTRKeypair.h" @@ -988,7 +989,7 @@ - (MTRDevice *)_setupDeviceForNodeID:(NSNumber *)nodeID prefetchedClusterData:(N { os_unfair_lock_assert_owner(&_deviceMapLock); - MTRDevice * deviceToReturn = [[MTRDevice alloc] initWithNodeID:nodeID controller:self]; + MTRDevice * deviceToReturn = [[MTRDevice_Concrete alloc] initWithNodeID:nodeID controller:self]; // If we're not running, don't add the device to our map. That would // create a cycle that nothing would break. Just return the device, // which will be in exactly the state it would be in if it were created diff --git a/src/darwin/Framework/CHIP/MTRDevice_Concrete.h b/src/darwin/Framework/CHIP/MTRDevice_Concrete.h new file mode 100644 index 00000000000000..6466a18c04abf6 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRDevice_Concrete.h @@ -0,0 +1,27 @@ +/** + * + * Copyright (c) 2022-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 +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface MTRDevice_Concrete : MTRDevice + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm new file mode 100644 index 00000000000000..c8b00ac622e311 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm @@ -0,0 +1,4220 @@ +/** + * + * Copyright (c) 2022-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 +#import + +#import "MTRAsyncWorkQueue.h" +#import "MTRAttributeSpecifiedCheck.h" +#import "MTRBaseClusters.h" +#import "MTRBaseDevice_Internal.h" +#import "MTRBaseSubscriptionCallback.h" +#import "MTRCluster.h" +#import "MTRClusterConstants.h" +#import "MTRCommandTimedCheck.h" +#import "MTRConversion.h" +#import "MTRDefines_Internal.h" +#import "MTRDeviceConnectivityMonitor.h" +#import "MTRDeviceControllerOverXPC.h" +#import "MTRDeviceController_Internal.h" +#import "MTRDevice_Concrete.h" +#import "MTRDevice_Internal.h" +#import "MTRError_Internal.h" +#import "MTREventTLVValueDecoder_Internal.h" +#import "MTRLogging_Internal.h" +#import "MTRMetricKeys.h" +#import "MTRMetricsCollector.h" +#import "MTRTimeUtils.h" +#import "MTRUnfairLock.h" +#import "MTRUtilities.h" +#import "zap-generated/MTRCommandPayloads_Internal.h" + +#import "lib/core/CHIPError.h" +#import "lib/core/DataModelTypes.h" +#import +#import + +#import +#import +#import +#import +#import +#import + +// allow readwrite access to superclass properties +@interface MTRDevice_Concrete () + +@property (nonatomic, readwrite, copy) NSNumber * nodeID; +@property (nonatomic, readwrite, nullable) MTRDeviceController * deviceController; +@property (nonatomic, readwrite) MTRAsyncWorkQueue * asyncWorkQueue; +@property (nonatomic, readwrite) MTRDeviceState state; +@property (nonatomic, readwrite, nullable) NSDate * estimatedStartTime; +@property (nonatomic, readwrite, nullable, copy) NSNumber * estimatedSubscriptionLatency; + +@end + +typedef void (^MTRDeviceAttributeReportHandler)(NSArray * _Nonnull); + +#define kSecondsToWaitBeforeMarkingUnreachableAfterSettingUpSubscription 10 + +// Disabling pending crashes +#define ENABLE_CONNECTIVITY_MONITORING 0 + +// Consider moving utility classes to their own file +#pragma mark - Utility Classes + +// container of MTRDevice delegate weak reference, its queue, and its interested paths for attribute reports +MTR_DIRECT_MEMBERS +@interface MTRDeviceDelegateInfo_ConcreteCopy : NSObject { +@private + void * _delegatePointerValue; + __weak id _delegate; + dispatch_queue_t _queue; + NSArray * _Nullable _interestedPathsForAttributes; + NSArray * _Nullable _interestedPathsForEvents; +} + +// Array of interested cluster paths, attribute paths, or endpointID, for attribute report filtering. +@property (readonly, nullable) NSArray * interestedPathsForAttributes; + +// Array of interested cluster paths, attribute paths, or endpointID, for event report filtering. +@property (readonly, nullable) NSArray * interestedPathsForEvents; + +// Expose delegate +@property (readonly) id delegate; + +// Pointer value for logging purpose only +@property (readonly) void * delegatePointerValue; + +- (instancetype)initWithDelegate:(id)delegate queue:(dispatch_queue_t)queue interestedPathsForAttributes:(NSArray * _Nullable)interestedPathsForAttributes interestedPathsForEvents:(NSArray * _Nullable)interestedPathsForEvents; + +// Returns YES if delegate and queue are both non-null, and the block is scheduled to run. +- (BOOL)callDelegateWithBlock:(void (^)(id))block; + +#ifdef DEBUG +// Only used for unit test purposes - normal delegate should not expect or handle being called back synchronously. +- (BOOL)callDelegateSynchronouslyWithBlock:(void (^)(id))block; +#endif +@end + +@implementation MTRDeviceDelegateInfo_ConcreteCopy +- (instancetype)initWithDelegate:(id)delegate queue:(dispatch_queue_t)queue interestedPathsForAttributes:(NSArray * _Nullable)interestedPathsForAttributes interestedPathsForEvents:(NSArray * _Nullable)interestedPathsForEvents +{ + if (self = [super init]) { + _delegate = delegate; + _delegatePointerValue = (__bridge void *) delegate; + _queue = queue; + _interestedPathsForAttributes = [interestedPathsForAttributes copy]; + _interestedPathsForEvents = [interestedPathsForEvents copy]; + } + return self; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"", self, _delegatePointerValue, static_cast(_interestedPathsForAttributes.count), static_cast(_interestedPathsForEvents.count)]; +} + +- (BOOL)callDelegateWithBlock:(void (^)(id))block +{ + id strongDelegate = _delegate; + VerifyOrReturnValue(strongDelegate, NO); + dispatch_async(_queue, ^{ + block(strongDelegate); + }); + return YES; +} + +#ifdef DEBUG +- (BOOL)callDelegateSynchronouslyWithBlock:(void (^)(id))block +{ + id strongDelegate = _delegate; + VerifyOrReturnValue(strongDelegate, NO); + + block(strongDelegate); + + return YES; +} +#endif +@end + +/* BEGIN DRAGONS: Note methods here cannot be renamed, and are used by private callers, do not rename, remove or modify behavior here */ + +@interface NSObject (MatterPrivateForInternalDragonsDoNotFeed) +- (void)_deviceInternalStateChanged:(MTRDevice *)device; +@end + +/* END DRAGONS */ + +#pragma mark - SubscriptionCallback class declaration +using namespace chip; +using namespace chip::app; +using namespace chip::Protocols::InteractionModel; +using namespace chip::Tracing::DarwinFramework; + +typedef void (^FirstReportHandler)(void); + +namespace { + +class SubscriptionCallback final : public MTRBaseSubscriptionCallback { +public: + SubscriptionCallback(DataReportCallback attributeReportCallback, DataReportCallback eventReportCallback, + ErrorCallback errorCallback, MTRDeviceResubscriptionScheduledHandler resubscriptionCallback, + SubscriptionEstablishedHandler subscriptionEstablishedHandler, OnDoneHandler onDoneHandler, + UnsolicitedMessageFromPublisherHandler unsolicitedMessageFromPublisherHandler, ReportBeginHandler reportBeginHandler, + ReportEndHandler reportEndHandler) + : MTRBaseSubscriptionCallback(attributeReportCallback, eventReportCallback, errorCallback, resubscriptionCallback, + subscriptionEstablishedHandler, onDoneHandler, unsolicitedMessageFromPublisherHandler, reportBeginHandler, + reportEndHandler) + { + } + + // Used to reset Resubscription backoff on events that indicate likely availability of device to come back online + void ResetResubscriptionBackoff() { mResubscriptionNumRetries = 0; } + +private: + void OnEventData(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus) override; + + void OnAttributeData(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus) override; + + CHIP_ERROR OnResubscriptionNeeded(chip::app::ReadClient * apReadClient, CHIP_ERROR aTerminationCause) override; + + // Copied from ReadClient and customized for MTRDevice resubscription time reset + uint32_t ComputeTimeTillNextSubscription(); + uint32_t mResubscriptionNumRetries = 0; +}; + +} // anonymous namespace + +#pragma mark - MTRDevice + +// Utility methods for working with MTRInternalDeviceState, located near the +// enum so it's easier to notice that they need to stay in sync. +namespace { +bool HadSubscriptionEstablishedOnce(MTRInternalDeviceState state) +{ + return state >= MTRInternalDeviceStateInitialSubscriptionEstablished; +} + +bool NeedToStartSubscriptionSetup(MTRInternalDeviceState state) +{ + return state <= MTRInternalDeviceStateUnsubscribed; +} + +bool HaveSubscriptionEstablishedRightNow(MTRInternalDeviceState state) +{ + return state == MTRInternalDeviceStateInitialSubscriptionEstablished || state == MTRInternalDeviceStateLaterSubscriptionEstablished; +} +} // anonymous namespace + +typedef NS_ENUM(NSUInteger, MTRDeviceExpectedValueFieldIndex) { + MTRDeviceExpectedValueFieldExpirationTimeIndex = 0, + MTRDeviceExpectedValueFieldValueIndex = 1, + MTRDeviceExpectedValueFieldIDIndex = 2 +}; + +typedef NS_ENUM(NSUInteger, MTRDeviceReadRequestFieldIndex) { + MTRDeviceReadRequestFieldPathIndex = 0, + MTRDeviceReadRequestFieldParamsIndex = 1 +}; + +typedef NS_ENUM(NSUInteger, MTRDeviceWriteRequestFieldIndex) { + MTRDeviceWriteRequestFieldPathIndex = 0, + MTRDeviceWriteRequestFieldValueIndex = 1, + MTRDeviceWriteRequestFieldTimeoutIndex = 2, + MTRDeviceWriteRequestFieldExpectedValueIDIndex = 3, +}; + +typedef NS_ENUM(NSUInteger, MTRDeviceWorkItemBatchingID) { + MTRDeviceWorkItemBatchingReadID = 1, + MTRDeviceWorkItemBatchingWriteID = 2, +}; + +typedef NS_ENUM(NSUInteger, MTRDeviceWorkItemDuplicateTypeID) { + MTRDeviceWorkItemDuplicateReadTypeID = 1, +}; + +// Minimal time to wait since our last resubscribe failure before we will allow +// a read attempt to prod our subscription. +// +// TODO: Figure out a better value for this, but for now don't allow this to +// happen more often than once every 10 minutes. +#define MTRDEVICE_MIN_RESUBSCRIBE_DUE_TO_READ_INTERVAL_SECONDS (10 * 60) + +// Weight of new data in determining subscription latencies. To avoid random +// outliers causing too much noise in the value, treat an existing value (if +// any) as having 2/3 weight and the new value as having 1/3 weight. These +// weights are subject to change, if it's determined that different ones give +// better behavior. +#define MTRDEVICE_SUBSCRIPTION_LATENCY_NEW_VALUE_WEIGHT (1.0 / 3.0) + +@interface MTRDevice_Concrete () +@property (nonatomic, readonly) os_unfair_lock lock; // protects the caches and device state +// protects against concurrent time updates by guarding timeUpdateScheduled flag which manages time updates scheduling, +// and protects device calls to setUTCTime and setDSTOffset +@property (nonatomic, readonly) os_unfair_lock timeSyncLock; +@property (nonatomic) chip::FabricIndex fabricIndex; +@property (nonatomic) NSMutableArray *> * unreportedEvents; +@property (nonatomic) BOOL receivingReport; +@property (nonatomic) BOOL receivingPrimingReport; + +// TODO: instead of all the BOOL properties that are some facet of the state, move to internal state machine that has (at least): +// Actively receiving report +// Actively receiving priming report + +@property (nonatomic) MTRInternalDeviceState internalDeviceState; + +#define MTRDEVICE_SUBSCRIPTION_ATTEMPT_MIN_WAIT_SECONDS (1) +#define MTRDEVICE_SUBSCRIPTION_ATTEMPT_MAX_WAIT_SECONDS (3600) +@property (nonatomic) uint32_t lastSubscriptionAttemptWait; + +/** + * If reattemptingSubscription is true, that means that we have failed to get a + * CASE session for the publisher and are now waiting to try again. In this + * state we never have subscriptionActive true or a non-null currentReadClient. + */ +@property (nonatomic) BOOL reattemptingSubscription; + +// Expected value cache is attributePath => NSArray of [NSDate of expiration time, NSDictionary of value, expected value ID] +// - See MTRDeviceExpectedValueFieldIndex for the definitions of indices into this array. +// See MTRDeviceResponseHandler definition for value dictionary details. +@property (nonatomic) NSMutableDictionary * expectedValueCache; + +// This is a monotonically increasing value used when adding entries to expectedValueCache +// Currently used/updated only in _getAttributesToReportWithNewExpectedValues:expirationTime:expectedValueID: +@property (nonatomic) uint64_t expectedValueNextID; + +@property (nonatomic) BOOL expirationCheckScheduled; + +@property (nonatomic) BOOL timeUpdateScheduled; + +@property (nonatomic) NSDate * estimatedStartTimeFromGeneralDiagnosticsUpTime; + +@property (nonatomic) NSMutableDictionary * temporaryMetaDataCache; + +/** + * If currentReadClient is non-null, that means that we successfully + * called SendAutoResubscribeRequest on the ReadClient and have not yet gotten + * an OnDone for that ReadClient. + */ +@property (nonatomic) ReadClient * currentReadClient; +@property (nonatomic) SubscriptionCallback * currentSubscriptionCallback; // valid when and only when currentReadClient is valid + +@end + +// Declaring selector so compiler won't complain about testing and calling it in _handleReportEnd +#ifdef DEBUG +@protocol MTRDeviceUnitTestDelegate +- (void)unitTestReportEndForDevice:(MTRDevice *)device; +- (BOOL)unitTestShouldSetUpSubscriptionForDevice:(MTRDevice *)device; +- (BOOL)unitTestShouldSkipExpectedValuesForWrite:(MTRDevice *)device; +- (NSNumber *)unitTestMaxIntervalOverrideForSubscription:(MTRDevice *)device; +- (BOOL)unitTestForceAttributeReportsIfMatchingCache:(MTRDevice *)device; +- (BOOL)unitTestPretendThreadEnabled:(MTRDevice *)device; +- (void)unitTestSubscriptionPoolDequeue:(MTRDevice *)device; +- (void)unitTestSubscriptionPoolWorkComplete:(MTRDevice *)device; +- (void)unitTestClusterDataPersisted:(MTRDevice *)device; +- (BOOL)unitTestSuppressTimeBasedReachabilityChanges:(MTRDevice *)device; +@end +#endif + +@implementation MTRDevice_Concrete { +#ifdef DEBUG + NSUInteger _unitTestAttributesReportedSinceLastCheck; +#endif + + // _deviceCachePrimed is true if we have the data that comes from an initial + // subscription priming report (whether it came from storage or from our + // subscription). + BOOL _deviceCachePrimed; + + // _persistedClusterData stores data that we have already persisted (when we have + // cluster data persistence enabled). Nil when we have no persistence enabled. + NSCache * _Nullable _persistedClusterData; + // _clusterDataToPersist stores data that needs to be persisted. If we + // don't have persistence enabled, this is our only data store. Nil if we + // currently have nothing that could need persisting. + NSMutableDictionary * _Nullable _clusterDataToPersist; + // _persistedClusters stores the set of "valid" keys into _persistedClusterData. + // These are keys that could have values in _persistedClusterData even if they don't + // right now (because they have been evicted). + NSMutableSet * _persistedClusters; + + // When we last failed to subscribe to the device (either via + // _setupSubscriptionWithReason or via the auto-resubscribe behavior + // of the ReadClient). Nil if we have had no such failures. + NSDate * _Nullable _lastSubscriptionFailureTime; + MTRDeviceConnectivityMonitor * _connectivityMonitor; + + // This boolean keeps track of any device configuration changes received in an attribute report. + // If this is true when the report ends, we notify the delegate. + BOOL _deviceConfigurationChanged; + + // The completion block is set when the subscription / resubscription work is enqueued, and called / cleared when any of the following happen: + // 1. Subscription establishes + // 2. OnResubscriptionNeeded is called + // 3. Subscription reset (including when getSessionForNode fails) + MTRAsyncWorkCompletionBlock _subscriptionPoolWorkCompletionBlock; + + // Tracking of initial subscribe latency. When _initialSubscribeStart is + // nil, we are not tracking the latency. + NSDate * _Nullable _initialSubscribeStart; + + // Storage behavior configuration and variables to keep track of the logic + // _clusterDataPersistenceFirstScheduledTime is used to track the start time of the delay between + // report and persistence. + // _mostRecentReportTimes is a list of the most recent report timestamps used for calculating + // the running average time between reports. + // _deviceReportingExcessivelyStartTime tracks when a device starts reporting excessively. + // _reportToPersistenceDelayCurrentMultiplier is the current multiplier that is calculated when a + // report comes in. + MTRDeviceStorageBehaviorConfiguration * _storageBehaviorConfiguration; + NSDate * _Nullable _clusterDataPersistenceFirstScheduledTime; + NSMutableArray * _mostRecentReportTimes; + NSDate * _Nullable _deviceReportingExcessivelyStartTime; + double _reportToPersistenceDelayCurrentMultiplier; + + // System time change observer reference + id _systemTimeChangeObserverToken; + + NSMutableSet * _delegates; +} + +// synthesize superclass property readwrite accessors +@synthesize nodeID = _nodeID; +@synthesize deviceController = _deviceController; +@synthesize queue = _queue; +@synthesize asyncWorkQueue = _asyncWorkQueue; +@synthesize state = _state; +@synthesize estimatedStartTime = _estimatedStartTime; +@synthesize estimatedSubscriptionLatency = _estimatedSubscriptionLatency; +//@synthesize lock = _lock; +//@synthesize persistedClusterData = _persistedClusterData; + +- (instancetype)initWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller +{ + // `super` was NSObject, is now MTRDevice. MTRDevice hides its `init` + if (self = [super initForSubclasses]) { + _lock = OS_UNFAIR_LOCK_INIT; + _timeSyncLock = OS_UNFAIR_LOCK_INIT; + _nodeID = [nodeID copy]; + _fabricIndex = controller.fabricIndex; + _deviceController = controller; + _queue + = dispatch_queue_create("org.csa-iot.matter.framework.device.workqueue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); + _expectedValueCache = [NSMutableDictionary dictionary]; + _asyncWorkQueue = [[MTRAsyncWorkQueue alloc] initWithContext:self]; + _state = MTRDeviceStateUnknown; + _internalDeviceState = MTRInternalDeviceStateUnsubscribed; + if (controller.controllerDataStore) { + _persistedClusterData = [[NSCache alloc] init]; + } else { + _persistedClusterData = nil; + } + _clusterDataToPersist = nil; + _persistedClusters = [NSMutableSet set]; + + // If there is a data store, make sure we have an observer to monitor system clock changes, so + // NSDate-based write coalescing could be reset and not get into a bad state. + if (_persistedClusterData) { + mtr_weakify(self); + _systemTimeChangeObserverToken = [[NSNotificationCenter defaultCenter] addObserverForName:NSSystemClockDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull notification) { + mtr_strongify(self); + std::lock_guard lock(self->_lock); + [self _resetStorageBehaviorState]; + }]; + } + + _delegates = [NSMutableSet set]; + + MTR_LOG_DEBUG("%@ init with hex nodeID 0x%016llX", self, _nodeID.unsignedLongLongValue); + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:_systemTimeChangeObserverToken]; + + // TODO: retain cycle and clean up https://github.com/project-chip/connectedhomeip/issues/34267 + MTR_LOG("MTRDevice dealloc: %p", self); +} + +- (NSString *)description +{ + return [NSString + stringWithFormat:@"[fabric: %u, nodeID: 0x%016llX]", self, _fabricIndex, _nodeID.unsignedLongLongValue]; +} + ++ (MTRDevice *)deviceWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller +{ + return [controller deviceForNodeID:nodeID]; +} + +#pragma mark - Time Synchronization + +- (void)_setTimeOnDevice +{ + NSDate * now = [NSDate date]; + // If no date available, error + if (!now) { + MTR_LOG_ERROR("%@ Could not retrieve current date. Unable to setUTCTime on endpoints.", self); + return; + } + + uint64_t matterEpochTimeMicroseconds = 0; + if (!DateToMatterEpochMicroseconds(now, matterEpochTimeMicroseconds)) { + MTR_LOG_ERROR("%@ Could not convert NSDate (%@) to Matter Epoch Time. Unable to setUTCTime on endpoints.", self, now); + return; + } + + // Set Time on each Endpoint with a Time Synchronization Cluster Server + NSArray * endpointsToSync = [self _endpointsWithTimeSyncClusterServer]; + for (NSNumber * endpoint in endpointsToSync) { + MTR_LOG_DEBUG("%@ Setting Time on Endpoint %@", self, endpoint); + [self _setUTCTime:matterEpochTimeMicroseconds withGranularity:MTRTimeSynchronizationGranularityMicrosecondsGranularity forEndpoint:endpoint]; + + // Check how many DST offsets this endpoint supports. + auto dstOffsetsMaxSizePath = [MTRAttributePath attributePathWithEndpointID:endpoint clusterID:@(MTRClusterIDTypeTimeSynchronizationID) attributeID:@(MTRAttributeIDTypeClusterTimeSynchronizationAttributeDSTOffsetListMaxSizeID)]; + auto dstOffsetsMaxSize = [self readAttributeWithEndpointID:dstOffsetsMaxSizePath.endpoint clusterID:dstOffsetsMaxSizePath.cluster attributeID:dstOffsetsMaxSizePath.attribute params:nil]; + if (dstOffsetsMaxSize == nil) { + // This endpoint does not support TZ, so won't support SetDSTOffset. + MTR_LOG("%@ Unable to SetDSTOffset on endpoint %@, since it does not support the TZ feature", self, endpoint); + continue; + } + auto attrReport = [[MTRAttributeReport alloc] initWithResponseValue:@{ + MTRAttributePathKey : dstOffsetsMaxSizePath, + MTRDataKey : dstOffsetsMaxSize, + } + error:nil]; + uint8_t maxOffsetCount; + if (attrReport == nil) { + MTR_LOG_ERROR("%@ DSTOffsetListMaxSize value on endpoint %@ is invalid. Defaulting to 1.", self, endpoint); + maxOffsetCount = 1; + } else { + NSNumber * maxOffsetCountAsNumber = attrReport.value; + maxOffsetCount = maxOffsetCountAsNumber.unsignedCharValue; + if (maxOffsetCount == 0) { + MTR_LOG_ERROR("%@ DSTOffsetListMaxSize value on endpoint %@ is 0, which is not allowed. Defaulting to 1.", self, endpoint); + maxOffsetCount = 1; + } + } + auto * dstOffsets = MTRComputeDSTOffsets(maxOffsetCount); + if (dstOffsets == nil) { + MTR_LOG_ERROR("%@ Could not retrieve DST offset information. Unable to setDSTOffset on endpoint %@.", self, endpoint); + continue; + } + + [self _setDSTOffsets:dstOffsets forEndpoint:endpoint]; + } +} + +- (void)_scheduleNextUpdate:(UInt64)nextUpdateInSeconds +{ + mtr_weakify(self); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (nextUpdateInSeconds * NSEC_PER_SEC)), self.queue, ^{ + MTR_LOG_DEBUG("%@ Timer expired, start Device Time Update", self); + mtr_strongify(self); + if (self) { + [self _performScheduledTimeUpdate]; + } else { + MTR_LOG_DEBUG("%@ MTRDevice no longer valid. No Timer Scheduled will be scheduled for a Device Time Update.", self); + return; + } + }); + self.timeUpdateScheduled = YES; + MTR_LOG_DEBUG("%@ Timer Scheduled for next Device Time Update, in %llu seconds", self, nextUpdateInSeconds); +} + +// Time Updates are a day apart (this can be changed in the future) +#define MTR_DEVICE_TIME_UPDATE_DEFAULT_WAIT_TIME_SEC (24 * 60 * 60) +// assume lock is held +- (void)_updateDeviceTimeAndScheduleNextUpdate +{ + os_unfair_lock_assert_owner(&self->_timeSyncLock); + if (self.timeUpdateScheduled) { + MTR_LOG_DEBUG("%@ Device Time Update already scheduled", self); + return; + } + + [self _setTimeOnDevice]; + [self _scheduleNextUpdate:MTR_DEVICE_TIME_UPDATE_DEFAULT_WAIT_TIME_SEC]; +} + +- (void)_performScheduledTimeUpdate +{ + std::lock_guard lock(_timeSyncLock); + // Device needs to still be reachable + if (self.state != MTRDeviceStateReachable) { + MTR_LOG_DEBUG("%@ Device is not reachable, canceling Device Time Updates.", self); + return; + } + // Device must not be invalidated + if (!self.timeUpdateScheduled) { + MTR_LOG_DEBUG("%@ Device Time Update is no longer scheduled, MTRDevice may have been invalidated.", self); + return; + } + self.timeUpdateScheduled = NO; + [self _updateDeviceTimeAndScheduleNextUpdate]; +} + +- (NSArray *)_endpointsWithTimeSyncClusterServer +{ + auto partsList = [self readAttributeWithEndpointID:@(0) clusterID:@(MTRClusterIDTypeDescriptorID) attributeID:@(MTRAttributeIDTypeClusterDescriptorAttributePartsListID) params:nil]; + NSMutableArray * endpointsOnDevice = [self arrayOfNumbersFromAttributeValue:partsList]; + if (!endpointsOnDevice) { + endpointsOnDevice = [[NSMutableArray alloc] init]; + } + // Add Root node! + [endpointsOnDevice addObject:@(0)]; + + NSMutableArray * endpointsWithTimeSyncCluster = [[NSMutableArray alloc] init]; + for (NSNumber * endpoint in endpointsOnDevice) { + // Get list of server clusters on endpoint + auto clusterList = [self readAttributeWithEndpointID:endpoint clusterID:@(MTRClusterIDTypeDescriptorID) attributeID:@(MTRAttributeIDTypeClusterDescriptorAttributeServerListID) params:nil]; + NSArray * clusterArray = [self arrayOfNumbersFromAttributeValue:clusterList]; + + if (clusterArray && [clusterArray containsObject:@(MTRClusterIDTypeTimeSynchronizationID)]) { + [endpointsWithTimeSyncCluster addObject:endpoint]; + } + } + MTR_LOG_DEBUG("%@ Device has following endpoints with Time Sync Cluster Server: %@", self, endpointsWithTimeSyncCluster); + return endpointsWithTimeSyncCluster; +} + +- (void)_setUTCTime:(UInt64)matterEpochTime withGranularity:(uint8_t)granularity forEndpoint:(NSNumber *)endpoint +{ + MTR_LOG_DEBUG(" %@ _setUTCTime with matterEpochTime: %llu, endpoint %@", self, matterEpochTime, endpoint); + MTRTimeSynchronizationClusterSetUTCTimeParams * params = [[MTRTimeSynchronizationClusterSetUTCTimeParams + alloc] init]; + params.utcTime = @(matterEpochTime); + params.granularity = @(granularity); + auto setUTCTimeResponseHandler = ^(id _Nullable response, NSError * _Nullable error) { + if (error) { + MTR_LOG_ERROR("%@ _setUTCTime failed on endpoint %@, with parameters %@, error: %@", self, endpoint, params, error); + } + }; + + [self _invokeKnownCommandWithEndpointID:endpoint + clusterID:@(MTRClusterIDTypeTimeSynchronizationID) + commandID:@(MTRCommandIDTypeClusterTimeSynchronizationCommandSetUTCTimeID) + commandPayload:params + expectedValues:nil + expectedValueInterval:nil + timedInvokeTimeout:nil + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:nil + queue:self.queue + completion:setUTCTimeResponseHandler]; +} + +- (void)_setDSTOffsets:(NSArray *)dstOffsets forEndpoint:(NSNumber *)endpoint +{ + MTR_LOG_DEBUG("%@ _setDSTOffsets with offsets: %@, endpoint %@", + self, dstOffsets, endpoint); + + MTRTimeSynchronizationClusterSetDSTOffsetParams * params = [[MTRTimeSynchronizationClusterSetDSTOffsetParams + alloc] init]; + params.dstOffset = dstOffsets; + + auto setDSTOffsetResponseHandler = ^(id _Nullable response, NSError * _Nullable error) { + if (error) { + MTR_LOG_ERROR("%@ _setDSTOffsets failed on endpoint %@, with parameters %@, error: %@", self, endpoint, params, error); + } + }; + + [self _invokeKnownCommandWithEndpointID:endpoint + clusterID:@(MTRClusterIDTypeTimeSynchronizationID) + commandID:@(MTRCommandIDTypeClusterTimeSynchronizationCommandSetDSTOffsetID) + commandPayload:params + expectedValues:nil + expectedValueInterval:nil + timedInvokeTimeout:nil + serverSideProcessingTimeout:params.serverSideProcessingTimeout + responseClass:nil + queue:self.queue + completion:setDSTOffsetResponseHandler]; +} + +- (NSMutableArray *)arrayOfNumbersFromAttributeValue:(MTRDeviceDataValueDictionary)dataDictionary +{ + if (![MTRArrayValueType isEqual:dataDictionary[MTRTypeKey]]) { + return nil; + } + + id value = dataDictionary[MTRValueKey]; + if (![value isKindOfClass:NSArray.class]) { + return nil; + } + + NSArray * valueArray = value; + __auto_type outputArray = [NSMutableArray arrayWithCapacity:valueArray.count]; + + for (id item in valueArray) { + if (![item isKindOfClass:NSDictionary.class]) { + return nil; + } + + NSDictionary * itemDictionary = item; + id data = itemDictionary[MTRDataKey]; + if (![data isKindOfClass:NSDictionary.class]) { + return nil; + } + + NSDictionary * dataDictionary = data; + id dataType = dataDictionary[MTRTypeKey]; + id dataValue = dataDictionary[MTRValueKey]; + if (![dataType isKindOfClass:NSString.class] || ![dataValue isKindOfClass:NSNumber.class]) { + return nil; + } + [outputArray addObject:dataValue]; + } + return outputArray; +} + +#pragma mark Subscription and delegate handling + +// subscription intervals are in seconds +#define MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MIN (10 * 60) // 10 minutes (for now) +#define MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MAX (60 * 60) // 60 minutes + +- (BOOL)_subscriptionsAllowed +{ + os_unfair_lock_assert_owner(&self->_lock); + + // We should not allow a subscription for device controllers over XPC. + return ![_deviceController isKindOfClass:MTRDeviceControllerOverXPC.class]; +} + +- (void)setDelegate:(id)delegate queue:(dispatch_queue_t)queue +{ + MTR_LOG("%@ setDelegate %@", self, delegate); + [self _addDelegate:delegate queue:queue interestedPathsForAttributes:nil interestedPathsForEvents:nil]; +} + +- (void)addDelegate:(id)delegate queue:(dispatch_queue_t)queue +{ + MTR_LOG("%@ addDelegate %@", self, delegate); + [self _addDelegate:delegate queue:queue interestedPathsForAttributes:nil interestedPathsForEvents:nil]; +} + +- (void)addDelegate:(id)delegate queue:(dispatch_queue_t)queue interestedPathsForAttributes:(NSArray * _Nullable)interestedPathsForAttributes interestedPathsForEvents:(NSArray * _Nullable)interestedPathsForEvents +{ + MTR_LOG("%@ addDelegate %@ with interested attribute paths %@ event paths %@", self, delegate, interestedPathsForAttributes, interestedPathsForEvents); + [self _addDelegate:delegate queue:queue interestedPathsForAttributes:interestedPathsForAttributes interestedPathsForEvents:interestedPathsForEvents]; +} + +- (void)_addDelegate:(id)delegate queue:(dispatch_queue_t)queue interestedPathsForAttributes:(NSArray * _Nullable)interestedPathsForAttributes interestedPathsForEvents:(NSArray * _Nullable)interestedPathsForEvents +{ + std::lock_guard lock(_lock); + + // Replace delegate info with the same delegate object, and opportunistically remove defunct delegate references + NSMutableSet * delegatesToRemove = [NSMutableSet set]; + for (MTRDeviceDelegateInfo_ConcreteCopy * delegateInfo in _delegates) { + id strongDelegate = delegateInfo.delegate; + if (!strongDelegate) { + [delegatesToRemove addObject:delegateInfo]; + MTR_LOG("%@ removing delegate info for nil delegate %p", self, delegateInfo.delegatePointerValue); + } else if (strongDelegate == delegate) { + [delegatesToRemove addObject:delegateInfo]; + MTR_LOG("%@ replacing delegate info for %p", self, delegate); + } + } + if (delegatesToRemove.count) { + NSUInteger oldDelegatesCount = _delegates.count; + [_delegates minusSet:delegatesToRemove]; + MTR_LOG("%@ addDelegate: removed %lu", self, static_cast(_delegates.count - oldDelegatesCount)); + } + + MTRDeviceDelegateInfo_ConcreteCopy * newDelegateInfo = [[MTRDeviceDelegateInfo_ConcreteCopy alloc] initWithDelegate:delegate queue:queue interestedPathsForAttributes:interestedPathsForAttributes interestedPathsForEvents:interestedPathsForEvents]; + [_delegates addObject:newDelegateInfo]; + MTR_LOG("%@ added delegate info %@", self, newDelegateInfo); + + __block BOOL shouldSetUpSubscription = [self _subscriptionsAllowed]; + + // For unit testing only. If this ever changes to not being for unit testing purposes, + // we would need to move the code outside of where we acquire the lock above. +#ifdef DEBUG + [self _callFirstDelegateSynchronouslyWithBlock:^(id testDelegate) { + if ([testDelegate respondsToSelector:@selector(unitTestShouldSetUpSubscriptionForDevice:)]) { + shouldSetUpSubscription = [testDelegate unitTestShouldSetUpSubscriptionForDevice:self]; + } + }]; +#endif + + if (shouldSetUpSubscription) { + MTR_LOG("%@ - starting subscription setup", self); + // Record the time of first addDelegate call that triggers initial subscribe, and do not reset this value on subsequent addDelegate calls + if (!_initialSubscribeStart) { + _initialSubscribeStart = [NSDate now]; + } + if ([self _deviceUsesThread]) { + MTR_LOG(" => %@ - device is a thread device, scheduling in pool", self); + [self _scheduleSubscriptionPoolWork:^{ + std::lock_guard lock(self->_lock); + [self _setupSubscriptionWithReason:@"delegate is set and scheduled subscription is happening"]; + } inNanoseconds:0 description:@"MTRDevice setDelegate first subscription"]; + } else { + [self _setupSubscriptionWithReason:@"delegate is set and subscription is needed"]; + } + } +} + +- (void)removeDelegate:(id)delegate +{ + MTR_LOG("%@ removeDelegate %@", self, delegate); + + std::lock_guard lock(_lock); + + NSMutableSet * delegatesToRemove = [NSMutableSet set]; + [self _iterateDelegatesWithBlock:^(MTRDeviceDelegateInfo_ConcreteCopy * delegateInfo) { + id strongDelegate = delegateInfo.delegate; + if (strongDelegate == delegate) { + [delegatesToRemove addObject:delegateInfo]; + MTR_LOG("%@ removing delegate info %@ for %p", self, delegateInfo, delegate); + } + }]; + if (delegatesToRemove.count) { + NSUInteger oldDelegatesCount = _delegates.count; + [_delegates minusSet:delegatesToRemove]; + MTR_LOG("%@ removeDelegate: removed %lu", self, static_cast(_delegates.count - oldDelegatesCount)); + } +} + +- (void)invalidate +{ + MTR_LOG("%@ invalidate", self); + + [_asyncWorkQueue invalidate]; + + os_unfair_lock_lock(&self->_timeSyncLock); + _timeUpdateScheduled = NO; + os_unfair_lock_unlock(&self->_timeSyncLock); + + os_unfair_lock_lock(&self->_lock); + + _state = MTRDeviceStateUnknown; + + [_delegates removeAllObjects]; + + // Make sure we don't try to resubscribe if we have a pending resubscribe + // attempt, since we now have no delegate. + _reattemptingSubscription = NO; + + [_deviceController asyncDispatchToMatterQueue:^{ + MTR_LOG("%@ invalidate disconnecting ReadClient and SubscriptionCallback", self); + + // Destroy the read client and callback (has to happen on the Matter + // queue, to avoid deleting objects that are being referenced), to + // tear down the subscription. We will get no more callbacks from + // the subscription after this point. + std::lock_guard lock(self->_lock); + self->_currentReadClient = nullptr; + if (self->_currentSubscriptionCallback) { + delete self->_currentSubscriptionCallback; + } + self->_currentSubscriptionCallback = nullptr; + + [self _changeInternalState:MTRInternalDeviceStateUnsubscribed]; + } + errorHandler:nil]; + + [self _stopConnectivityMonitoring]; + + os_unfair_lock_unlock(&self->_lock); +} + +- (void)nodeMayBeAdvertisingOperational +{ + assertChipStackLockedByCurrentThread(); + + MTR_LOG("%@ saw new operational advertisement", self); + + [self _triggerResubscribeWithReason:@"operational advertisement seen" + nodeLikelyReachable:YES]; +} + +// Trigger a resubscribe as needed. nodeLikelyReachable should be YES if we +// have reason to suspect the node is now reachable, NO if we have no idea +// whether it might be. +- (void)_triggerResubscribeWithReason:(NSString *)reason nodeLikelyReachable:(BOOL)nodeLikelyReachable +{ + MTR_LOG("%@ _triggerResubscribeWithReason called with reason %@", self, reason); + assertChipStackLockedByCurrentThread(); + + // We might want to trigger a resubscribe on our existing ReadClient. Do + // that outside the scope of our lock, so we're not calling arbitrary code + // we don't control with the lock held. This is safe, because we are + // running on he Matter queue and the ReadClient can't get destroyed while + // we are on that queue. + ReadClient * readClientToResubscribe = nullptr; + SubscriptionCallback * subscriptionCallback = nullptr; + + os_unfair_lock_lock(&self->_lock); + + // Don't change state to MTRDeviceStateReachable, since the device might not + // in fact be reachable yet; we won't know until we have managed to + // establish a CASE session. And at that point, our subscription will + // trigger the state change as needed. + if (self.reattemptingSubscription) { + [self _reattemptSubscriptionNowIfNeededWithReason:reason]; + } else { + readClientToResubscribe = self->_currentReadClient; + subscriptionCallback = self->_currentSubscriptionCallback; + } + os_unfair_lock_unlock(&self->_lock); + + if (readClientToResubscribe) { + if (nodeLikelyReachable) { + // If we have reason to suspect the node is now reachable, reset the + // backoff timer, so that if this attempt fails we'll try again + // quickly; it's possible we'll just catch the node at a bad time + // here (e.g. still booting up), but should try again reasonably quickly. + subscriptionCallback->ResetResubscriptionBackoff(); + } + readClientToResubscribe->TriggerResubscribeIfScheduled(reason.UTF8String); + } +} + +// Return YES if we are in a state where, apart from communication issues with +// the device, we will be able to get reports via our subscription. +- (BOOL)_subscriptionAbleToReport +{ + std::lock_guard lock(_lock); + if (![self _delegateExists]) { + // No delegate definitely means no subscription. + return NO; + } + + // For unit testing only, matching logic in setDelegate +#ifdef DEBUG + __block BOOL useTestDelegateOverride = NO; + __block BOOL testDelegateShouldSetUpSubscriptionForDevice = NO; + [self _callFirstDelegateSynchronouslyWithBlock:^(id testDelegate) { + if ([testDelegate respondsToSelector:@selector(unitTestShouldSetUpSubscriptionForDevice:)]) { + useTestDelegateOverride = YES; + testDelegateShouldSetUpSubscriptionForDevice = [testDelegate unitTestShouldSetUpSubscriptionForDevice:self]; + } + }]; + if (useTestDelegateOverride && !testDelegateShouldSetUpSubscriptionForDevice) { + return NO; + } + +#endif + + // Subscriptions are not able to report if they are not allowed. + return [self _subscriptionsAllowed]; +} + +// Notification that read-through was skipped for an attribute read. +- (void)_readThroughSkipped +{ + std::lock_guard lock(_lock); + if (_state == MTRDeviceStateReachable) { + // We're getting reports from the device, so there's nothing else to be + // done here. We could skip this check, because our "try to + // resubscribe" code would be a no-op in this case, but then we'd have + // an extra dispatch in the common case of read-while-subscribed, which + // is not great for peformance. + return; + } + + if (_lastSubscriptionFailureTime == nil) { + // No need to try to do anything here, because we have never failed a + // subscription attempt (so we might be in the middle of one now, and no + // need to prod things along). + return; + } + + if ([[NSDate now] timeIntervalSinceDate:_lastSubscriptionFailureTime] < MTRDEVICE_MIN_RESUBSCRIBE_DUE_TO_READ_INTERVAL_SECONDS) { + // Not enough time has passed since we last tried. Don't create extra + // network traffic. + // + // TODO: Do we need to worry about this being too spammy in the log if + // we keep getting reads while not subscribed? We could add another + // backoff timer or counter for the log line... + MTR_LOG_DEBUG("%@ skipping resubscribe from skipped read-through: not enough time has passed since %@", self, _lastSubscriptionFailureTime); + return; + } + + // Do the remaining work on the Matter queue, because we may want to touch + // ReadClient in there. If the dispatch fails, that's fine; it means our + // controller has shut down, so nothing to be done. + [_deviceController asyncDispatchToMatterQueue:^{ + [self _triggerResubscribeWithReason:@"read-through skipped while not subscribed" nodeLikelyReachable:NO]; + } + errorHandler:nil]; +} + +- (BOOL)_delegateExists +{ + os_unfair_lock_assert_owner(&self->_lock); + return [self _iterateDelegatesWithBlock:nil]; +} + +// Returns YES if any non-null delegates were found +- (BOOL)_iterateDelegatesWithBlock:(void(NS_NOESCAPE ^)(MTRDeviceDelegateInfo_ConcreteCopy * delegateInfo)_Nullable)block +{ + os_unfair_lock_assert_owner(&self->_lock); + + if (!_delegates.count) { + MTR_LOG_DEBUG("%@ no delegates to iterate", self); + return NO; + } + + // Opportunistically remove defunct delegate references on every iteration + NSMutableSet * delegatesToRemove = nil; + for (MTRDeviceDelegateInfo_ConcreteCopy * delegateInfo in _delegates) { + id strongDelegate = delegateInfo.delegate; + if (strongDelegate) { + if (block) { + @autoreleasepool { + block(delegateInfo); + } + } + (void) strongDelegate; // ensure it stays alive + } else { + if (!delegatesToRemove) { + delegatesToRemove = [NSMutableSet set]; + } + [delegatesToRemove addObject:delegateInfo]; + } + } + + if (delegatesToRemove.count) { + [_delegates minusSet:delegatesToRemove]; + MTR_LOG("%@ _iterateDelegatesWithBlock: removed %lu remaining %lu", self, static_cast(delegatesToRemove.count), (unsigned long) static_cast(_delegates.count)); + } + + return (_delegates.count > 0); +} + +- (BOOL)_callDelegatesWithBlock:(void (^)(id delegate))block +{ + os_unfair_lock_assert_owner(&self->_lock); + + __block NSUInteger delegatesCalled = 0; + [self _iterateDelegatesWithBlock:^(MTRDeviceDelegateInfo_ConcreteCopy * delegateInfo) { + if ([delegateInfo callDelegateWithBlock:block]) { + delegatesCalled++; + } + }]; + + return (delegatesCalled > 0); +} + +#ifdef DEBUG +// Only used for unit test purposes - normal delegate should not expect or handle being called back synchronously +// Returns YES if a delegate is called +- (void)_callFirstDelegateSynchronouslyWithBlock:(void (^)(id delegate))block +{ + os_unfair_lock_assert_owner(&self->_lock); + + for (MTRDeviceDelegateInfo_ConcreteCopy * delegateInfo in _delegates) { + if ([delegateInfo callDelegateSynchronouslyWithBlock:block]) { + MTR_LOG("%@ _callFirstDelegateSynchronouslyWithBlock: successfully called %@", self, delegateInfo); + return; + } + } +} +#endif + +- (void)_callDelegateDeviceCachePrimed +{ + os_unfair_lock_assert_owner(&self->_lock); + [self _callDelegatesWithBlock:^(id delegate) { + if ([delegate respondsToSelector:@selector(deviceCachePrimed:)]) { + [delegate deviceCachePrimed:self]; + } + }]; +} + +// assume lock is held +- (void)_changeState:(MTRDeviceState)state +{ + os_unfair_lock_assert_owner(&self->_lock); + MTRDeviceState lastState = _state; + _state = state; + if (lastState != state) { + if (state != MTRDeviceStateReachable) { + MTR_LOG("%@ reachability state change %lu => %lu, set estimated start time to nil", self, static_cast(lastState), + static_cast(state)); + _estimatedStartTime = nil; + _estimatedStartTimeFromGeneralDiagnosticsUpTime = nil; + } else { + MTR_LOG( + "%@ reachability state change %lu => %lu", self, static_cast(lastState), static_cast(state)); + } + [self _callDelegatesWithBlock:^(id delegate) { + [delegate device:self stateChanged:state]; + }]; + } else { + MTR_LOG( + "%@ Not reporting reachability state change, since no change in state %lu => %lu", self, static_cast(lastState), static_cast(state)); + } +} + +- (void)_changeInternalState:(MTRInternalDeviceState)state +{ + os_unfair_lock_assert_owner(&self->_lock); + MTRInternalDeviceState lastState = _internalDeviceState; + _internalDeviceState = state; + if (lastState != state) { + MTR_LOG("%@ internal state change %lu => %lu", self, static_cast(lastState), static_cast(state)); + + /* BEGIN DRAGONS: This is a huge hack for a specific use case, do not rename, remove or modify behavior here */ + // TODO: This should only be called for thread devices + [self _callDelegatesWithBlock:^(id delegate) { + if ([delegate respondsToSelector:@selector(_deviceInternalStateChanged:)]) { + [delegate _deviceInternalStateChanged:self]; + } + }]; + /* END DRAGONS */ + } +} + +#ifdef DEBUG +- (MTRInternalDeviceState)_getInternalState +{ + std::lock_guard lock(self->_lock); + return _internalDeviceState; +} +#endif + +// First Time Sync happens 2 minutes after reachability (this can be changed in the future) +#define MTR_DEVICE_TIME_UPDATE_INITIAL_WAIT_TIME_SEC (60 * 2) +- (void)_handleSubscriptionEstablished +{ + os_unfair_lock_lock(&self->_lock); + + // We have completed the subscription work - remove from the subscription pool. + [self _clearSubscriptionPoolWork]; + + // reset subscription attempt wait time when subscription succeeds + _lastSubscriptionAttemptWait = 0; + if (HadSubscriptionEstablishedOnce(_internalDeviceState)) { + [self _changeInternalState:MTRInternalDeviceStateLaterSubscriptionEstablished]; + } else { + MATTER_LOG_METRIC_END(kMetricMTRDeviceInitialSubscriptionSetup, CHIP_NO_ERROR); + [self _changeInternalState:MTRInternalDeviceStateInitialSubscriptionEstablished]; + } + + [self _changeState:MTRDeviceStateReachable]; + + // No need to monitor connectivity after subscription establishment + [self _stopConnectivityMonitoring]; + + auto initialSubscribeStart = _initialSubscribeStart; + // We no longer need to track subscribe latency for this device. + _initialSubscribeStart = nil; + + if (initialSubscribeStart != nil) { + // We want time interval from initialSubscribeStart to now, not the other + // way around. + NSTimeInterval subscriptionLatency = -[initialSubscribeStart timeIntervalSinceNow]; + if (_estimatedSubscriptionLatency == nil) { + _estimatedSubscriptionLatency = @(subscriptionLatency); + } else { + NSTimeInterval newSubscriptionLatencyEstimate = MTRDEVICE_SUBSCRIPTION_LATENCY_NEW_VALUE_WEIGHT * subscriptionLatency + (1 - MTRDEVICE_SUBSCRIPTION_LATENCY_NEW_VALUE_WEIGHT) * _estimatedSubscriptionLatency.doubleValue; + _estimatedSubscriptionLatency = @(newSubscriptionLatencyEstimate); + } + [self _storePersistedDeviceData]; + } + + os_unfair_lock_unlock(&self->_lock); + + os_unfair_lock_lock(&self->_timeSyncLock); + + if (!self.timeUpdateScheduled) { + [self _scheduleNextUpdate:MTR_DEVICE_TIME_UPDATE_INITIAL_WAIT_TIME_SEC]; + } + + os_unfair_lock_unlock(&self->_timeSyncLock); +} + +- (void)_handleSubscriptionError:(NSError *)error +{ + std::lock_guard lock(_lock); + [self _doHandleSubscriptionError:error]; +} + +- (void)_doHandleSubscriptionError:(NSError *)error +{ + os_unfair_lock_assert_owner(&_lock); + + [self _changeInternalState:MTRInternalDeviceStateUnsubscribed]; + _unreportedEvents = nil; + + [self _changeState:MTRDeviceStateUnreachable]; +} + +- (BOOL)deviceUsesThread +{ + std::lock_guard lock(_lock); + return [self _deviceUsesThread]; +} + +// This method is used for signaling whether to use the subscription pool. This functions as +// a heuristic for whether to throttle subscriptions to the device via a pool of subscriptions. +// If products appear that have both Thread and Wifi enabled but are primarily on wifi, this +// method will need to be updated to reflect that. +- (BOOL)_deviceUsesThread +{ + os_unfair_lock_assert_owner(&self->_lock); + +#ifdef DEBUG + // Note: This is a hack to allow our unit tests to test the subscription pooling behavior we have implemented for thread, so we mock devices to be a thread device + __block BOOL pretendThreadEnabled = NO; + [self _callFirstDelegateSynchronouslyWithBlock:^(id testDelegate) { + if ([testDelegate respondsToSelector:@selector(unitTestPretendThreadEnabled:)]) { + pretendThreadEnabled = [testDelegate unitTestPretendThreadEnabled:self]; + } + }]; + if (pretendThreadEnabled) { + return YES; + } +#endif + + MTRClusterPath * networkCommissioningClusterPath = [MTRClusterPath clusterPathWithEndpointID:@(kRootEndpointId) clusterID:@(MTRClusterIDTypeNetworkCommissioningID)]; + MTRDeviceClusterData * networkCommissioningClusterData = [self _clusterDataForPath:networkCommissioningClusterPath]; + NSNumber * networkCommissioningClusterFeatureMapValueNumber = networkCommissioningClusterData.attributes[@(MTRClusterGlobalAttributeFeatureMapID)][MTRValueKey]; + + if (networkCommissioningClusterFeatureMapValueNumber == nil) + return NO; + if (![networkCommissioningClusterFeatureMapValueNumber isKindOfClass:[NSNumber class]]) { + MTR_LOG_ERROR("%@ Unexpected NetworkCommissioning FeatureMap value %@", self, networkCommissioningClusterFeatureMapValueNumber); + return NO; + } + + uint32_t networkCommissioningClusterFeatureMapValue = static_cast(networkCommissioningClusterFeatureMapValueNumber.unsignedLongValue); + + return (networkCommissioningClusterFeatureMapValue & MTRNetworkCommissioningFeatureThreadNetworkInterface) != 0 ? YES : NO; +} + +- (void)_clearSubscriptionPoolWork +{ + os_unfair_lock_assert_owner(&self->_lock); + MTRAsyncWorkCompletionBlock completion = self->_subscriptionPoolWorkCompletionBlock; + if (completion) { +#ifdef DEBUG + [self _callDelegatesWithBlock:^(id testDelegate) { + if ([testDelegate respondsToSelector:@selector(unitTestSubscriptionPoolWorkComplete:)]) { + [testDelegate unitTestSubscriptionPoolWorkComplete:self]; + } + }]; +#endif + self->_subscriptionPoolWorkCompletionBlock = nil; + completion(MTRAsyncWorkComplete); + } +} + +- (void)_scheduleSubscriptionPoolWork:(dispatch_block_t)workBlock inNanoseconds:(int64_t)inNanoseconds description:(NSString *)description +{ + os_unfair_lock_assert_owner(&self->_lock); + + // Sanity check we are not scheduling for this device multiple times in the pool + if (_subscriptionPoolWorkCompletionBlock) { + MTR_LOG("%@ already scheduled in subscription pool for this device - ignoring: %@", self, description); + return; + } + + // Wait the required amount of time, then put it in the subscription pool to wait additionally for a spot, if needed + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, inNanoseconds), dispatch_get_main_queue(), ^{ + // In the case where a resubscription triggering event happened and already established, running the work block should result in a no-op + MTRAsyncWorkItem * workItem = [[MTRAsyncWorkItem alloc] initWithQueue:self.queue]; + [workItem setReadyHandler:^(id _Nonnull context, NSInteger retryCount, MTRAsyncWorkCompletionBlock _Nonnull completion) { + MTR_LOG("%@ - work item is ready to attempt pooled subscription", self); + os_unfair_lock_lock(&self->_lock); +#ifdef DEBUG + [self _callDelegatesWithBlock:^(id testDelegate) { + if ([testDelegate respondsToSelector:@selector(unitTestSubscriptionPoolDequeue:)]) { + [testDelegate unitTestSubscriptionPoolDequeue:self]; + } + }]; +#endif + if (self->_subscriptionPoolWorkCompletionBlock) { + // This means a resubscription triggering event happened and is now in-progress + MTR_LOG("%@ timer fired but already running in subscription pool - ignoring: %@", self, description); + os_unfair_lock_unlock(&self->_lock); + + // call completion as complete to remove from queue + completion(MTRAsyncWorkComplete); + return; + } + + // Otherwise, save the completion block + self->_subscriptionPoolWorkCompletionBlock = completion; + os_unfair_lock_unlock(&self->_lock); + + workBlock(); + }]; + [self->_deviceController.concurrentSubscriptionPool enqueueWorkItem:workItem description:description]; + MTR_LOG("%@ - enqueued in the subscription pool", self); + }); +} + +- (void)_handleResubscriptionNeededWithDelay:(NSNumber *)resubscriptionDelayMs +{ + BOOL deviceUsesThread; + + os_unfair_lock_lock(&self->_lock); + + [self _changeState:MTRDeviceStateUnknown]; + [self _changeInternalState:MTRInternalDeviceStateResubscribing]; + + // If we are here, then the ReadClient either just detected a subscription + // drop or just tried again and failed. Either way, count it as "tried and + // failed to subscribe": in the latter case it's actually true, and in the + // former case we recently had a subscription and do not want to be forcing + // retries immediately. + _lastSubscriptionFailureTime = [NSDate now]; + + deviceUsesThread = [self _deviceUsesThread]; + + // If a previous resubscription failed, remove the item from the subscription pool. + [self _clearSubscriptionPoolWork]; + + os_unfair_lock_unlock(&self->_lock); + + // Use the existing _triggerResubscribeWithReason mechanism, which does the right checks when + // this block is run -- if other triggering events had happened, this would become a no-op. + auto resubscriptionBlock = ^{ + [self->_deviceController asyncDispatchToMatterQueue:^{ + [self _triggerResubscribeWithReason:@"ResubscriptionNeeded timer fired" nodeLikelyReachable:NO]; + } errorHandler:^(NSError * _Nonnull error) { + // If controller is not running, clear work item from the subscription queue + MTR_LOG_ERROR("%@ could not dispatch to matter queue for resubscription - error %@", self, error); + std::lock_guard lock(self->_lock); + [self _clearSubscriptionPoolWork]; + }]; + }; + + int64_t resubscriptionDelayNs = static_cast(resubscriptionDelayMs.unsignedIntValue * NSEC_PER_MSEC); + if (deviceUsesThread) { + std::lock_guard lock(_lock); + // For Thread-enabled devices, schedule the _triggerResubscribeWithReason call to run in the subscription pool + [self _scheduleSubscriptionPoolWork:resubscriptionBlock inNanoseconds:resubscriptionDelayNs description:@"ReadClient resubscription"]; + } else { + // For non-Thread-enabled devices, just call the resubscription block after the specified time + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, resubscriptionDelayNs), self.queue, resubscriptionBlock); + } + + // Set up connectivity monitoring in case network routability changes for the positive, to accelerate resubscription + [self _setupConnectivityMonitoring]; +} + +- (void)_handleSubscriptionReset:(NSNumber * _Nullable)retryDelay +{ + std::lock_guard lock(_lock); + [self _doHandleSubscriptionReset:retryDelay]; +} + +- (void)_doHandleSubscriptionReset:(NSNumber * _Nullable)retryDelay +{ + os_unfair_lock_assert_owner(&_lock); + + // If we are here, then either we failed to establish initial CASE, or we + // failed to send the initial SubscribeRequest message, or our ReadClient + // has given up completely. Those all count as "we have tried and failed to + // subscribe". + _lastSubscriptionFailureTime = [NSDate now]; + + // if there is no delegate then also do not retry + if (![self _delegateExists]) { + // NOTE: Do not log anything here: we have been invalidated, and the + // Matter stack might already be torn down. + return; + } + + // don't schedule multiple retries + if (self.reattemptingSubscription) { + return; + } + + self.reattemptingSubscription = YES; + + NSTimeInterval secondsToWait; + if (_lastSubscriptionAttemptWait < MTRDEVICE_SUBSCRIPTION_ATTEMPT_MIN_WAIT_SECONDS) { + _lastSubscriptionAttemptWait = MTRDEVICE_SUBSCRIPTION_ATTEMPT_MIN_WAIT_SECONDS; + secondsToWait = _lastSubscriptionAttemptWait; + } else if (retryDelay != nil) { + // The device responded but is currently busy. Reset our backoff + // counter, so that we don't end up waiting for a long time if the next + // attempt fails for some reason, and retry after whatever time period + // the device told us to use. + _lastSubscriptionAttemptWait = 0; + secondsToWait = retryDelay.doubleValue; + MTR_LOG("%@ resetting resubscribe attempt counter, and delaying by the server-provided delay: %f", + self, secondsToWait); + } else { + _lastSubscriptionAttemptWait *= 2; + if (_lastSubscriptionAttemptWait > MTRDEVICE_SUBSCRIPTION_ATTEMPT_MAX_WAIT_SECONDS) { + _lastSubscriptionAttemptWait = MTRDEVICE_SUBSCRIPTION_ATTEMPT_MAX_WAIT_SECONDS; + } + secondsToWait = _lastSubscriptionAttemptWait; + } + + MTR_LOG("%@ scheduling to reattempt subscription in %f seconds", self, secondsToWait); + + // If we started subscription or session establishment but failed, remove item from the subscription pool so we can re-queue. + [self _clearSubscriptionPoolWork]; + + // Call _reattemptSubscriptionNowIfNeededWithReason when timer fires - if subscription is + // in a better state at that time this will be a no-op. + auto resubscriptionBlock = ^{ + std::lock_guard lock(self->_lock); + [self _reattemptSubscriptionNowIfNeededWithReason:@"got subscription reset"]; + }; + + int64_t resubscriptionDelayNs = static_cast(secondsToWait * NSEC_PER_SEC); + if ([self _deviceUsesThread]) { + // For Thread-enabled devices, schedule the _reattemptSubscriptionNowIfNeededWithReason call to run in the subscription pool + [self _scheduleSubscriptionPoolWork:resubscriptionBlock inNanoseconds:resubscriptionDelayNs description:@"MTRDevice resubscription"]; + } else { + // For non-Thread-enabled devices, just call the resubscription block after the specified time + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, resubscriptionDelayNs), self.queue, resubscriptionBlock); + } +} + +- (void)_reattemptSubscriptionNowIfNeededWithReason:(NSString *)reason +{ + os_unfair_lock_assert_owner(&self->_lock); + if (!self.reattemptingSubscription) { + return; + } + + MTR_LOG("%@ reattempting subscription with reason %@", self, reason); + self.reattemptingSubscription = NO; + [self _setupSubscriptionWithReason:reason]; +} + +- (void)_handleUnsolicitedMessageFromPublisher +{ + std::lock_guard lock(_lock); + + [self _changeState:MTRDeviceStateReachable]; + + [self _callDelegatesWithBlock:^(id delegate) { + if ([delegate respondsToSelector:@selector(deviceBecameActive:)]) { + [delegate deviceBecameActive:self]; + } + }]; + + // in case this is called during exponential back off of subscription + // reestablishment, this starts the attempt right away + // TODO: This doesn't really make sense. If we _don't_ have a live + // ReadClient how did we get this notification and if we _do_ have an active + // ReadClient, this call or _setupSubscriptionWithReason would be no-ops. + [self _reattemptSubscriptionNowIfNeededWithReason:@"got unsolicited message from publisher"]; +} + +- (void)_markDeviceAsUnreachableIfNeverSubscribed +{ + os_unfair_lock_assert_owner(&self->_lock); + + if (HadSubscriptionEstablishedOnce(_internalDeviceState)) { + return; + } + + MTR_LOG("%@ still not subscribed, marking the device as unreachable", self); + [self _changeState:MTRDeviceStateUnreachable]; +} + +- (void)_handleReportBegin +{ + std::lock_guard lock(_lock); + + _receivingReport = YES; + if (_state != MTRDeviceStateReachable) { + [self _changeState:MTRDeviceStateReachable]; + } + + // If we currently don't have an established subscription, this must be a + // priming report. + _receivingPrimingReport = !HaveSubscriptionEstablishedRightNow(_internalDeviceState); +} + +- (NSDictionary *)_clusterDataToPersistSnapshot +{ + os_unfair_lock_assert_owner(&self->_lock); + NSMutableDictionary * clusterDataToReturn = [NSMutableDictionary dictionary]; + for (MTRClusterPath * clusterPath in _clusterDataToPersist) { + clusterDataToReturn[clusterPath] = [_clusterDataToPersist[clusterPath] copy]; + } + + return clusterDataToReturn; +} + +- (NSTimeInterval)_reportToPersistenceDelayTimeAfterMutiplier +{ + return _storageBehaviorConfiguration.reportToPersistenceDelayTime * _reportToPersistenceDelayCurrentMultiplier; +} + +- (NSTimeInterval)_reportToPersistenceDelayTimeMaxAfterMutiplier +{ + return _storageBehaviorConfiguration.reportToPersistenceDelayTimeMax * _reportToPersistenceDelayCurrentMultiplier; +} + +- (BOOL)_dataStoreExists +{ + os_unfair_lock_assert_owner(&self->_lock); + return _persistedClusterData != nil; +} + +- (void)_persistClusterData +{ + os_unfair_lock_assert_owner(&self->_lock); + + // Sanity check + if (![self _dataStoreExists]) { + MTR_LOG_ERROR("%@ storage behavior: no data store in _persistClusterData!", self); + return; + } + + // Nothing to persist + if (!_clusterDataToPersist.count) { + return; + } + + MTR_LOG("%@ Storing cluster information (data version and attributes) count: %lu", self, static_cast(_clusterDataToPersist.count)); + // We're going to hand out these MTRDeviceClusterData objects to our + // storage implementation, which will try to read them later. Make sure + // we snapshot the state here instead of handing out live copies. + NSDictionary * clusterData = [self _clusterDataToPersistSnapshot]; + [_deviceController.controllerDataStore storeClusterData:clusterData forNodeID:_nodeID]; + for (MTRClusterPath * clusterPath in _clusterDataToPersist) { + [_persistedClusterData setObject:_clusterDataToPersist[clusterPath] forKey:clusterPath]; + [_persistedClusters addObject:clusterPath]; + } + + // TODO: There is one edge case not handled well here: if the + // storeClusterData call above fails somehow, and then the data gets + // evicted from _persistedClusterData, we could end up in a situation + // where when we page things in from storage we have stale values and + // hence effectively lose the delta that we failed to persist. + // + // The only way to handle this would be to detect it when it happens, + // then re-subscribe at that point, which would cause the relevant data + // to be sent to us via the priming read. + _clusterDataToPersist = nil; + +#ifdef DEBUG + [self _callDelegatesWithBlock:^(id testDelegate) { + if ([testDelegate respondsToSelector:@selector(unitTestClusterDataPersisted:)]) { + [testDelegate unitTestClusterDataPersisted:self]; + } + }]; +#endif +} + +- (BOOL)_deviceIsReportingExcessively +{ + os_unfair_lock_assert_owner(&self->_lock); + + if (!_deviceReportingExcessivelyStartTime) { + return NO; + } + + NSTimeInterval intervalSinceDeviceReportingExcessively = -[_deviceReportingExcessivelyStartTime timeIntervalSinceNow]; + BOOL deviceIsReportingExcessively = intervalSinceDeviceReportingExcessively > _storageBehaviorConfiguration.deviceReportingExcessivelyIntervalThreshold; + if (deviceIsReportingExcessively) { + MTR_LOG("%@ storage behavior: device has been reporting excessively for %.3lf seconds", self, intervalSinceDeviceReportingExcessively); + } + return deviceIsReportingExcessively; +} + +- (void)_persistClusterDataAsNeeded +{ + std::lock_guard lock(_lock); + + // Nothing to persist + if (!_clusterDataToPersist.count) { + return; + } + + // This is run with a dispatch_after, and need to check again if this device is reporting excessively + if ([self _deviceIsReportingExcessively]) { + return; + } + + NSDate * lastReportTime = [_mostRecentReportTimes lastObject]; + NSTimeInterval intervalSinceLastReport = -[lastReportTime timeIntervalSinceNow]; + if (intervalSinceLastReport < [self _reportToPersistenceDelayTimeAfterMutiplier]) { + // A report came in after this call was scheduled + + if (!_clusterDataPersistenceFirstScheduledTime) { + MTR_LOG_ERROR("%@ storage behavior: expects _clusterDataPersistenceFirstScheduledTime if _clusterDataToPersist exists", self); + return; + } + + NSTimeInterval intervalSinceFirstScheduledPersistence = -[_clusterDataPersistenceFirstScheduledTime timeIntervalSinceNow]; + if (intervalSinceFirstScheduledPersistence < [self _reportToPersistenceDelayTimeMaxAfterMutiplier]) { + MTR_LOG("%@ storage behavior: not persisting: intervalSinceLastReport %lf intervalSinceFirstScheduledPersistence %lf", self, intervalSinceLastReport, intervalSinceFirstScheduledPersistence); + // The max delay is also not reached - do not persist yet + return; + } + } + + // At this point, there is data to persist, and either _reportToPersistenceDelayTime was + // reached, or _reportToPersistenceDelayTimeMax was reached. Time to persist: + [self _persistClusterData]; + + _clusterDataPersistenceFirstScheduledTime = nil; +} + +#ifdef DEBUG +- (void)unitTestSetMostRecentReportTimes:(NSMutableArray *)mostRecentReportTimes +{ + _mostRecentReportTimes = mostRecentReportTimes; +} +#endif + +- (void)_scheduleClusterDataPersistence +{ + os_unfair_lock_assert_owner(&self->_lock); + + // No persisted data / lack of controller data store + if (![self _dataStoreExists]) { + MTR_LOG_DEBUG("%@ storage behavior: no data store", self); + return; + } + + // Nothing to persist + if (!_clusterDataToPersist.count) { + MTR_LOG_DEBUG("%@ storage behavior: nothing to persist", self); + return; + } + + // If there is no storage behavior configuration, make a default one + if (!_storageBehaviorConfiguration) { + _storageBehaviorConfiguration = [[MTRDeviceStorageBehaviorConfiguration alloc] init]; + [_storageBehaviorConfiguration checkValuesAndResetToDefaultIfNecessary]; + } + + // Directly store if the storage behavior optimization is disabled + if (_storageBehaviorConfiguration.disableStorageBehaviorOptimization) { + [self _persistClusterData]; + return; + } + + // If we have nothing stored at all yet, store directly, so we move into a + // primed state. + if (!_deviceCachePrimed) { + [self _persistClusterData]; + return; + } + + // Ensure there is an array to keep the most recent report times + if (!_mostRecentReportTimes) { + _mostRecentReportTimes = [NSMutableArray array]; + } + + // Mark when first report comes in to know when _reportToPersistenceDelayTimeMax is hit + if (!_clusterDataPersistenceFirstScheduledTime) { + _clusterDataPersistenceFirstScheduledTime = [NSDate now]; + } + + // Make sure there is space in the array, and note report time + while (_mostRecentReportTimes.count >= _storageBehaviorConfiguration.recentReportTimesMaxCount) { + [_mostRecentReportTimes removeObjectAtIndex:0]; + } + [_mostRecentReportTimes addObject:[NSDate now]]; + + // Calculate running average and update multiplier - need at least 2 items to calculate intervals + if (_mostRecentReportTimes.count > 2) { + NSTimeInterval cumulativeIntervals = 0; + for (int i = 1; i < _mostRecentReportTimes.count; i++) { + NSDate * lastDate = [_mostRecentReportTimes objectAtIndex:i - 1]; + NSDate * currentDate = [_mostRecentReportTimes objectAtIndex:i]; + NSTimeInterval intervalSinceLastReport = [currentDate timeIntervalSinceDate:lastDate]; + // Check to guard against clock change + if (intervalSinceLastReport > 0) { + cumulativeIntervals += intervalSinceLastReport; + } + } + NSTimeInterval averageTimeBetweenReports = cumulativeIntervals / (_mostRecentReportTimes.count - 1); + + if (averageTimeBetweenReports < _storageBehaviorConfiguration.timeBetweenReportsTooShortThreshold) { + // Multiplier goes from 1 to _reportToPersistenceDelayMaxMultiplier uniformly, as + // averageTimeBetweenReports go from timeBetweenReportsTooShortThreshold to + // timeBetweenReportsTooShortMinThreshold + + double intervalAmountBelowThreshold = _storageBehaviorConfiguration.timeBetweenReportsTooShortThreshold - averageTimeBetweenReports; + double intervalAmountBetweenThresholdAndMinThreshold = _storageBehaviorConfiguration.timeBetweenReportsTooShortThreshold - _storageBehaviorConfiguration.timeBetweenReportsTooShortMinThreshold; + double proportionTowardMinThreshold = intervalAmountBelowThreshold / intervalAmountBetweenThresholdAndMinThreshold; + if (proportionTowardMinThreshold > 1) { + // Clamp to 100% + proportionTowardMinThreshold = 1; + } + + // Set current multiplier to [1, MaxMultiplier] + _reportToPersistenceDelayCurrentMultiplier = 1 + (proportionTowardMinThreshold * (_storageBehaviorConfiguration.reportToPersistenceDelayMaxMultiplier - 1)); + MTR_LOG("%@ storage behavior: device reporting frequently - setting delay multiplier to %lf", self, _reportToPersistenceDelayCurrentMultiplier); + } else { + _reportToPersistenceDelayCurrentMultiplier = 1; + } + + // Also note when the running average first dips below the min threshold + if (averageTimeBetweenReports < _storageBehaviorConfiguration.timeBetweenReportsTooShortMinThreshold) { + if (!_deviceReportingExcessivelyStartTime) { + _deviceReportingExcessivelyStartTime = [NSDate now]; + MTR_LOG_DEBUG("%@ storage behavior: device is reporting excessively @%@", self, _deviceReportingExcessivelyStartTime); + } + } else { + _deviceReportingExcessivelyStartTime = nil; + } + } + + // Do not schedule persistence if device is reporting excessively + if ([self _deviceIsReportingExcessively]) { + return; + } + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) ([self _reportToPersistenceDelayTimeAfterMutiplier] * NSEC_PER_SEC)), self.queue, ^{ + [self _persistClusterDataAsNeeded]; + }); +} + +// Used to clear the storage behavior state when needed (system time change, or when new +// configuration is set. +// +// Also flushes unwritten cluster data to storage, if data store exists. +- (void)_resetStorageBehaviorState +{ + os_unfair_lock_assert_owner(&self->_lock); + + _clusterDataPersistenceFirstScheduledTime = nil; + _mostRecentReportTimes = nil; + _deviceReportingExcessivelyStartTime = nil; + _reportToPersistenceDelayCurrentMultiplier = 1; + + // Sanity check that there is a data + if ([self _dataStoreExists]) { + [self _persistClusterData]; + } +} + +- (void)setStorageBehaviorConfiguration:(MTRDeviceStorageBehaviorConfiguration *)storageBehaviorConfiguration +{ + MTR_LOG("%@ storage behavior: setStorageBehaviorConfiguration %@", self, storageBehaviorConfiguration); + std::lock_guard lock(_lock); + _storageBehaviorConfiguration = storageBehaviorConfiguration; + // Make sure the values are sane + [_storageBehaviorConfiguration checkValuesAndResetToDefaultIfNecessary]; + [self _resetStorageBehaviorState]; +} + +- (void)_handleReportEnd +{ + std::lock_guard lock(_lock); + _receivingReport = NO; + _receivingPrimingReport = NO; + _estimatedStartTimeFromGeneralDiagnosticsUpTime = nil; + + [self _scheduleClusterDataPersistence]; + + // After the handling of the report, if we detected a device configuration change, notify the delegate + // of the same. + if (_deviceConfigurationChanged) { + [self _callDelegatesWithBlock:^(id delegate) { + if ([delegate respondsToSelector:@selector(deviceConfigurationChanged:)]) { + [delegate deviceConfigurationChanged:self]; + } + }]; + _deviceConfigurationChanged = NO; + } + + // Do this after the _deviceConfigurationChanged check, so that we don't + // call deviceConfigurationChanged: immediately after telling our delegate + // we are now primed. + // + // TODO: Maybe we shouldn't dispatch deviceConfigurationChanged: for the + // initial priming bits? + if (!_deviceCachePrimed) { + // This is the end of the priming sequence of data reports, so we have + // all the data for the device now. + _deviceCachePrimed = YES; + [self _callDelegateDeviceCachePrimed]; + } + +// For unit testing only +#ifdef DEBUG + [self _callDelegatesWithBlock:^(id testDelegate) { + if ([testDelegate respondsToSelector:@selector(unitTestReportEndForDevice:)]) { + [testDelegate unitTestReportEndForDevice:self]; + } + }]; +#endif +} + +- (BOOL)_interestedPaths:(NSArray * _Nullable)interestedPaths includesAttributePath:(MTRAttributePath *)attributePath +{ + for (id interestedPath in interestedPaths) { + if ([interestedPath isKindOfClass:[NSNumber class]]) { + NSNumber * interestedEndpointIDNumber = interestedPath; + if ([interestedEndpointIDNumber isEqualToNumber:attributePath.endpoint]) { + return YES; + } + } else if ([interestedPath isKindOfClass:[MTRClusterPath class]]) { + MTRClusterPath * interestedClusterPath = interestedPath; + if ([interestedClusterPath.cluster isEqualToNumber:attributePath.cluster]) { + return YES; + } + } else if ([interestedPath isKindOfClass:[MTRAttributePath class]]) { + MTRAttributePath * interestedAttributePath = interestedPath; + if (([interestedAttributePath.cluster isEqualToNumber:attributePath.cluster]) && ([interestedAttributePath.attribute isEqualToNumber:attributePath.attribute])) { + return YES; + } + } + } + + return NO; +} + +// Returns filtered set of attributes using an interestedPaths array. +// Returns nil if no attribute report has a path that matches the paths in the interestedPaths array. +- (NSArray *> *)_filteredAttributes:(NSArray *> *)attributes forInterestedPaths:(NSArray * _Nullable)interestedPaths +{ + if (!interestedPaths) { + return attributes; + } + + if (!interestedPaths.count) { + return nil; + } + + NSMutableArray * filteredAttributes = nil; + for (NSDictionary * responseValue in attributes) { + MTRAttributePath * attributePath = responseValue[MTRAttributePathKey]; + if ([self _interestedPaths:interestedPaths includesAttributePath:attributePath]) { + if (!filteredAttributes) { + filteredAttributes = [NSMutableArray array]; + } + [filteredAttributes addObject:responseValue]; + } + } + + if (filteredAttributes.count && (filteredAttributes.count != attributes.count)) { + MTR_LOG("%@ filtered attribute report %lu => %lu", self, static_cast(attributes.count), static_cast(filteredAttributes.count)); + } + + return filteredAttributes; +} + +// assume lock is held +- (void)_reportAttributes:(NSArray *> *)attributes +{ + os_unfair_lock_assert_owner(&self->_lock); + if (attributes.count) { + [self _iterateDelegatesWithBlock:^(MTRDeviceDelegateInfo_ConcreteCopy * delegateInfo) { + // _iterateDelegatesWithBlock calls this with an autorelease pool, and so temporary filtered attributes reports don't bloat memory + NSArray *> * filteredAttributes = [self _filteredAttributes:attributes forInterestedPaths:delegateInfo.interestedPathsForAttributes]; + if (filteredAttributes.count) { + [delegateInfo callDelegateWithBlock:^(id delegate) { + [delegate device:self receivedAttributeReport:filteredAttributes]; + }]; + } + }]; + } +} + +- (void)_handleAttributeReport:(NSArray *> *)attributeReport fromSubscription:(BOOL)isFromSubscription +{ + std::lock_guard lock(_lock); + + // _getAttributesToReportWithReportedValues will log attribute paths reported + [self _reportAttributes:[self _getAttributesToReportWithReportedValues:attributeReport fromSubscription:isFromSubscription]]; +} + +#ifdef DEBUG +- (void)unitTestInjectEventReport:(NSArray *> *)eventReport +{ + dispatch_async(self.queue, ^{ + [self _handleEventReport:eventReport]; + }); +} + +- (void)unitTestInjectAttributeReport:(NSArray *> *)attributeReport fromSubscription:(BOOL)isFromSubscription +{ + dispatch_async(self.queue, ^{ + [self _handleReportBegin]; + [self _handleAttributeReport:attributeReport fromSubscription:isFromSubscription]; + [self _handleReportEnd]; + }); +} +#endif + +- (BOOL)_interestedPaths:(NSArray * _Nullable)interestedPaths includesEventPath:(MTREventPath *)eventPath +{ + for (id interestedPath in interestedPaths) { + if ([interestedPath isKindOfClass:[NSNumber class]]) { + NSNumber * interestedEndpointIDNumber = interestedPath; + if ([interestedEndpointIDNumber isEqualToNumber:eventPath.endpoint]) { + return YES; + } + } else if ([interestedPath isKindOfClass:[MTRClusterPath class]]) { + MTRClusterPath * interestedClusterPath = interestedPath; + if ([interestedClusterPath.cluster isEqualToNumber:eventPath.cluster]) { + return YES; + } + } else if ([interestedPath isKindOfClass:[MTREventPath class]]) { + MTREventPath * interestedEventPath = interestedPath; + if (([interestedEventPath.cluster isEqualToNumber:eventPath.cluster]) && ([interestedEventPath.event isEqualToNumber:eventPath.event])) { + return YES; + } + } + } + + return NO; +} + +// Returns filtered set of events using an interestedPaths array. +// Returns nil if no event report has a path that matches the paths in the interestedPaths array. +- (NSArray *> *)_filteredEvents:(NSArray *> *)events forInterestedPaths:(NSArray * _Nullable)interestedPaths +{ + if (!interestedPaths) { + return events; + } + + if (!interestedPaths.count) { + return nil; + } + + NSMutableArray * filteredEvents = nil; + for (NSDictionary * responseValue in events) { + MTREventPath * eventPath = responseValue[MTREventPathKey]; + if ([self _interestedPaths:interestedPaths includesEventPath:eventPath]) { + if (!filteredEvents) { + filteredEvents = [NSMutableArray array]; + } + [filteredEvents addObject:responseValue]; + } + } + + if (filteredEvents.count && (filteredEvents.count != events.count)) { + MTR_LOG("%@ filtered event report %lu => %lu", self, static_cast(events.count), static_cast(filteredEvents.count)); + } + + return filteredEvents; +} + +- (void)_handleEventReport:(NSArray *> *)eventReport +{ + std::lock_guard lock(_lock); + + NSDate * oldEstimatedStartTime = _estimatedStartTime; + // Combine with previous unreported events, if they exist + NSMutableArray * reportToReturn; + if (_unreportedEvents) { + reportToReturn = _unreportedEvents; + } else { + reportToReturn = [NSMutableArray array]; + } + for (NSDictionary * eventDict in eventReport) { + // Whenever a StartUp event is received, reset the estimated start time + // New subscription case + // - Starts Unreachable + // - Start CASE and send subscription request + // - Receive priming report ReportBegin + // - Optionally receive UpTime attribute - update time and save start time estimate + // - Optionally receive StartUp event + // - Set estimated system time from event receipt time, or saved UpTime estimate if exists + // - ReportEnd handler clears the saved start time estimate based on UpTime + // Subscription dropped from client point of view case + // - Starts Unreachable + // - Resubscribe happens after some time, and then same as the above + // Server resuming subscription after reboot case + // - Starts Reachable + // - Receive priming report ReportBegin + // - Optionally receive UpTime attribute - update time and save value + // - Optionally receive StartUp event + // - Set estimated system time from event receipt time, or saved UpTime estimate if exists + // - ReportEnd handler clears the saved start time estimate based on UpTime + // Server resuming subscription after timeout case + // - Starts Reachable + // - Receive priming report ReportBegin + // - Optionally receive UpTime attribute - update time and save value + // - ReportEnd handler clears the saved start time estimate based on UpTime + MTREventPath * eventPath = eventDict[MTREventPathKey]; + BOOL isStartUpEvent = (eventPath.cluster.unsignedLongValue == MTRClusterIDTypeBasicInformationID) + && (eventPath.event.unsignedLongValue == MTREventIDTypeClusterBasicInformationEventStartUpID); + if (isStartUpEvent) { + if (_estimatedStartTimeFromGeneralDiagnosticsUpTime) { + // If UpTime was received, make use of it as mark of system start time + MTR_LOG("%@ StartUp event: set estimated start time forward to %@", self, + _estimatedStartTimeFromGeneralDiagnosticsUpTime); + _estimatedStartTime = _estimatedStartTimeFromGeneralDiagnosticsUpTime; + } else { + // If UpTime was not received, reset estimated start time in case of reboot + MTR_LOG("%@ StartUp event: set estimated start time to nil", self); + _estimatedStartTime = nil; + } + } + + // If event time is of MTREventTimeTypeSystemUpTime type, then update estimated start time as needed + NSNumber * eventTimeTypeNumber = eventDict[MTREventTimeTypeKey]; + if (!eventTimeTypeNumber) { + MTR_LOG_ERROR("%@ Event %@ missing event time type", self, eventDict); + continue; + } + MTREventTimeType eventTimeType = (MTREventTimeType) eventTimeTypeNumber.unsignedIntegerValue; + if (eventTimeType == MTREventTimeTypeSystemUpTime) { + NSNumber * eventTimeValueNumber = eventDict[MTREventSystemUpTimeKey]; + if (!eventTimeValueNumber) { + MTR_LOG_ERROR("%@ Event %@ missing event time value", self, eventDict); + continue; + } + NSTimeInterval eventTimeValue = eventTimeValueNumber.doubleValue; + NSDate * potentialSystemStartTime = [NSDate dateWithTimeIntervalSinceNow:-eventTimeValue]; + if (!_estimatedStartTime || ([potentialSystemStartTime compare:_estimatedStartTime] == NSOrderedAscending)) { + _estimatedStartTime = potentialSystemStartTime; + } + } + + NSMutableDictionary * eventToReturn = eventDict.mutableCopy; + if (_receivingPrimingReport) { + eventToReturn[MTREventIsHistoricalKey] = @(YES); + } else { + eventToReturn[MTREventIsHistoricalKey] = @(NO); + } + + [reportToReturn addObject:eventToReturn]; + } + if (oldEstimatedStartTime != _estimatedStartTime) { + MTR_LOG("%@ updated estimated start time to %@", self, _estimatedStartTime); + } + + __block BOOL delegatesCalled = NO; + [self _iterateDelegatesWithBlock:^(MTRDeviceDelegateInfo_ConcreteCopy * delegateInfo) { + // _iterateDelegatesWithBlock calls this with an autorelease pool, and so temporary filtered event reports don't bloat memory + NSArray *> * filteredEvents = [self _filteredEvents:reportToReturn forInterestedPaths:delegateInfo.interestedPathsForEvents]; + if (filteredEvents.count) { + [delegateInfo callDelegateWithBlock:^(id delegate) { + [delegate device:self receivedEventReport:filteredEvents]; + }]; + delegatesCalled = YES; + } + }]; + if (delegatesCalled) { + _unreportedEvents = nil; + } else { + // save unreported events + _unreportedEvents = reportToReturn; + } +} + +#ifdef DEBUG +- (void)unitTestClearClusterData +{ + std::lock_guard lock(_lock); + NSAssert([self _dataStoreExists], @"Test is not going to test what it thinks is testing!"); + [_persistedClusterData removeAllObjects]; +} +#endif + +- (void)_reconcilePersistedClustersWithStorage +{ + os_unfair_lock_assert_owner(&self->_lock); + + NSMutableSet * clusterPathsToRemove = [NSMutableSet set]; + for (MTRClusterPath * clusterPath in _persistedClusters) { + MTRDeviceClusterData * data = [_deviceController.controllerDataStore getStoredClusterDataForNodeID:_nodeID endpointID:clusterPath.endpoint clusterID:clusterPath.cluster]; + if (!data) { + [clusterPathsToRemove addObject:clusterPath]; + } + } + + MTR_LOG_ERROR("%@ Storage missing %lu / %lu clusters - reconciling in-memory records", self, static_cast(clusterPathsToRemove.count), static_cast(_persistedClusters.count)); + [_persistedClusters minusSet:clusterPathsToRemove]; +} + +- (nullable MTRDeviceClusterData *)_clusterDataForPath:(MTRClusterPath *)clusterPath +{ + os_unfair_lock_assert_owner(&self->_lock); + + if (_clusterDataToPersist != nil) { + // Use the "dirty" values, if we have them. + MTRDeviceClusterData * data = _clusterDataToPersist[clusterPath]; + if (data != nil) { + return data; + } + } + + if ([self _dataStoreExists]) { + MTRDeviceClusterData * data = [_persistedClusterData objectForKey:clusterPath]; + if (data != nil) { + return data; + } + } + + if (![_persistedClusters containsObject:clusterPath]) { + // We are not expected to have this cluster, so no point in paging it in + // loading it from storage. + return nil; + } + + NSAssert(_deviceController.controllerDataStore != nil, + @"How can _persistedClusters have an entry if we have no persistence?"); + NSAssert(_persistedClusterData != nil, + @"How can _persistedClusterData not exist if we have persisted clusters?"); + + // Page in the stored value for the data. + MTRDeviceClusterData * data = [_deviceController.controllerDataStore getStoredClusterDataForNodeID:_nodeID endpointID:clusterPath.endpoint clusterID:clusterPath.cluster]; + MTR_LOG("%@ cluster path %@ cache miss - load from storage success %@", self, clusterPath, YES_NO(data)); + if (data != nil) { + [_persistedClusterData setObject:data forKey:clusterPath]; + } else { + // If clusterPath is in _persistedClusters and the data store returns nil for it, then the in-memory cache is now not dependable, and subscription should be reset and reestablished to reload cache from device + + // First make sure _persistedClusters is consistent with storage, so repeated calls don't immediately re-trigger this + [self _reconcilePersistedClustersWithStorage]; + + [self _resetSubscriptionWithReasonString:[NSString stringWithFormat:@"Data store has no data for cluster %@", clusterPath]]; + } + + return data; +} + +- (NSSet *)_knownClusters +{ + os_unfair_lock_assert_owner(&self->_lock); + + // We might have some clusters that have not been persisted at all yet, and + // some that have been persisted but are still present in + // _clusterDataToPersist because they have been modified since then. + NSMutableSet * clusterPaths = [_persistedClusters mutableCopy]; + if (_clusterDataToPersist != nil) { + [clusterPaths unionSet:[NSSet setWithArray:[_clusterDataToPersist allKeys]]]; + } + return clusterPaths; +} + +- (NSDictionary *)_getCachedDataVersions +{ + NSMutableDictionary * dataVersions = [NSMutableDictionary dictionary]; + std::lock_guard lock(_lock); + + for (MTRClusterPath * path in [self _knownClusters]) { + dataVersions[path] = [self _clusterDataForPath:path].dataVersion; + } + + MTR_LOG_DEBUG("%@ _getCachedDataVersions dataVersions count: %lu", self, static_cast(dataVersions.count)); + + return dataVersions; +} + +- (MTRDeviceDataValueDictionary _Nullable)_cachedAttributeValueForPath:(MTRAttributePath *)path +{ + os_unfair_lock_assert_owner(&self->_lock); + + // We need an actual MTRClusterPath, not a subsclass, to do _clusterDataForPath. + auto * clusterPath = [MTRClusterPath clusterPathWithEndpointID:path.endpoint clusterID:path.cluster]; + + MTRDeviceClusterData * clusterData = [self _clusterDataForPath:clusterPath]; + if (clusterData == nil) { + return nil; + } + + return clusterData.attributes[path.attribute]; +} + +- (void)_setCachedAttributeValue:(MTRDeviceDataValueDictionary _Nullable)value forPath:(MTRAttributePath *)path fromSubscription:(BOOL)isFromSubscription +{ + os_unfair_lock_assert_owner(&self->_lock); + + // We need an actual MTRClusterPath, not a subclass, to do _clusterDataForPath. + auto * clusterPath = [MTRClusterPath clusterPathWithEndpointID:path.endpoint clusterID:path.cluster]; + + MTRDeviceClusterData * clusterData = [self _clusterDataForPath:clusterPath]; + if (clusterData == nil) { + if (value == nil) { + // Nothing to do. + return; + } + + clusterData = [[MTRDeviceClusterData alloc] init]; + } + + [clusterData storeValue:value forAttribute:path.attribute]; + + if (value != nil + && isFromSubscription + && !_receivingPrimingReport + && AttributeHasChangesOmittedQuality(path)) { + // Do not persist new values for Changes Omitted Quality (aka C Quality) + // attributes unless they're part of a Priming Report or from a read response. + // (removals are OK) + + // log when a device violates expectations for Changes Omitted Quality attributes. + using namespace chip::Tracing::DarwinFramework; + MATTER_LOG_METRIC_BEGIN(kMetricUnexpectedCQualityUpdate); + [self _addInformationalAttributesToCurrentMetricScope]; + MATTER_LOG_METRIC_END(kMetricUnexpectedCQualityUpdate); + + return; + } + + if (_clusterDataToPersist == nil) { + _clusterDataToPersist = [NSMutableDictionary dictionary]; + } + _clusterDataToPersist[clusterPath] = clusterData; +} + +- (void)_removeCachedAttribute:(NSNumber *)attributeID fromCluster:(MTRClusterPath *)clusterPath +{ + os_unfair_lock_assert_owner(&self->_lock); + + if (_clusterDataToPersist == nil) { + return; + } + auto * clusterData = _clusterDataToPersist[clusterPath]; + [clusterData removeValueForAttribute:attributeID]; +} + +- (void)_createDataVersionFilterListFromDictionary:(NSDictionary *)dataVersions dataVersionFilterList:(DataVersionFilter **)dataVersionFilterList count:(size_t *)count +{ + size_t dataVersionFilterSize = dataVersions.count; + + // Check if any filter list should be generated + if (dataVersionFilterSize == 0) { + *count = 0; + *dataVersionFilterList = nullptr; + return; + } + + DataVersionFilter * dataVersionFilterArray = new DataVersionFilter[dataVersionFilterSize]; + size_t i = 0; + for (MTRClusterPath * path in dataVersions) { + NSNumber * dataVersionNumber = dataVersions[path]; + dataVersionFilterArray[i++] = DataVersionFilter(static_cast(path.endpoint.unsignedShortValue), static_cast(path.cluster.unsignedLongValue), static_cast(dataVersionNumber.unsignedLongValue)); + } + + *dataVersionFilterList = dataVersionFilterArray; + *count = dataVersionFilterSize; +} + +- (void)_setupConnectivityMonitoring +{ +#if ENABLE_CONNECTIVITY_MONITORING + // Dispatch to own queue first to avoid deadlock with syncGetCompressedFabricID + dispatch_async(self.queue, ^{ + // Get the required info before setting up the connectivity monitor + NSNumber * compressedFabricID = [self->_deviceController syncGetCompressedFabricID]; + if (!compressedFabricID) { + MTR_LOG_ERROR("%@ could not get compressed fabricID", self); + return; + } + + // Now lock for _connectivityMonitor + std::lock_guard lock(self->_lock); + if (self->_connectivityMonitor) { + // already monitoring + return; + } + + self->_connectivityMonitor = [[MTRDeviceConnectivityMonitor alloc] initWithCompressedFabricID:compressedFabricID nodeID:self.nodeID]; + [self->_connectivityMonitor startMonitoringWithHandler:^{ + [self->_deviceController asyncDispatchToMatterQueue:^{ + [self _triggerResubscribeWithReason:@"device connectivity changed" nodeLikelyReachable:YES]; + } + errorHandler:nil]; + } queue:self.queue]; + }); +#endif +} + +- (void)_stopConnectivityMonitoring +{ + os_unfair_lock_assert_owner(&_lock); + + if (_connectivityMonitor) { + [_connectivityMonitor stopMonitoring]; + _connectivityMonitor = nil; + } +} + +- (void)_resetSubscriptionWithReasonString:(NSString *)reasonString +{ + os_unfair_lock_assert_owner(&self->_lock); + MTR_LOG_ERROR("%@ %@ - resetting subscription", self, reasonString); + + [_deviceController asyncDispatchToMatterQueue:^{ + MTR_LOG("%@ subscription reset disconnecting ReadClient and SubscriptionCallback", self); + + std::lock_guard lock(self->_lock); + self->_currentReadClient = nullptr; + if (self->_currentSubscriptionCallback) { + delete self->_currentSubscriptionCallback; + } + self->_currentSubscriptionCallback = nullptr; + + [self _doHandleSubscriptionError:nil]; + // Use nil reset delay so that this keeps existing backoff timing + [self _doHandleSubscriptionReset:nil]; + } + errorHandler:nil]; +} + +#ifdef DEBUG +- (void)unitTestResetSubscription +{ + std::lock_guard lock(self->_lock); + [self _resetSubscriptionWithReasonString:@"Unit test reset subscription"]; +} +#endif + +// assume lock is held +- (void)_setupSubscriptionWithReason:(NSString *)reason +{ + os_unfair_lock_assert_owner(&self->_lock); + + if (![self _subscriptionsAllowed]) { + MTR_LOG("%@ _setupSubscription: Subscriptions not allowed. Do not set up subscription (reason: %@)", self, reason); + return; + } + +#ifdef DEBUG + __block NSNumber * delegateMin = nil; + Optional maxIntervalOverride; + [self _callFirstDelegateSynchronouslyWithBlock:^(id testDelegate) { + if ([testDelegate respondsToSelector:@selector(unitTestMaxIntervalOverrideForSubscription:)]) { + delegateMin = [testDelegate unitTestMaxIntervalOverrideForSubscription:self]; + } + }]; + if (delegateMin) { + maxIntervalOverride.Emplace(delegateMin.unsignedIntValue); + } +#endif + + // for now just subscribe once + if (!NeedToStartSubscriptionSetup(_internalDeviceState)) { + MTR_LOG("%@ setupSubscription: no need to subscribe due to internal state %lu (reason: %@)", self, static_cast(_internalDeviceState), reason); + return; + } + + [self _changeInternalState:MTRInternalDeviceStateSubscribing]; + + MTR_LOG("%@ setting up subscription with reason: %@", self, reason); + + __block bool markUnreachableAfterWait = true; +#ifdef DEBUG + [self _callFirstDelegateSynchronouslyWithBlock:^(id testDelegate) { + if ([testDelegate respondsToSelector:@selector(unitTestSuppressTimeBasedReachabilityChanges:)]) { + markUnreachableAfterWait = ![testDelegate unitTestSuppressTimeBasedReachabilityChanges:self]; + } + }]; +#endif + + if (markUnreachableAfterWait) { + // Set up a timer to mark as not reachable if it takes too long to set up a subscription + mtr_weakify(self); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, static_cast(kSecondsToWaitBeforeMarkingUnreachableAfterSettingUpSubscription) * static_cast(NSEC_PER_SEC)), self.queue, ^{ + mtr_strongify(self); + if (self != nil) { + std::lock_guard lock(self->_lock); + [self _markDeviceAsUnreachableIfNeverSubscribed]; + } + }); + } + + // This marks begin of initial subscription to the device (before CASE is established). The end is only marked after successfully setting + // up the subscription since it is always retried as long as the MTRDevice is kept running. + MATTER_LOG_METRIC_BEGIN(kMetricMTRDeviceInitialSubscriptionSetup); + + // Call directlyGetSessionForNode because the subscription setup already goes through the subscription pool queue + [_deviceController + directlyGetSessionForNode:_nodeID.unsignedLongLongValue + completion:^(chip::Messaging::ExchangeManager * _Nullable exchangeManager, + const chip::Optional & session, NSError * _Nullable error, + NSNumber * _Nullable retryDelay) { + if (error != nil) { + MTR_LOG_ERROR("%@ getSessionForNode error %@", self, error); + dispatch_async(self.queue, ^{ + [self _handleSubscriptionError:error]; + [self _handleSubscriptionReset:retryDelay]; + }); + return; + } + + auto callback = std::make_unique( + ^(NSArray * value) { + MTR_LOG("%@ got attribute report %@", self, value); + dispatch_async(self.queue, ^{ + // OnAttributeData + [self _handleAttributeReport:value fromSubscription:YES]; +#ifdef DEBUG + self->_unitTestAttributesReportedSinceLastCheck += value.count; +#endif + }); + }, + ^(NSArray * value) { + MTR_LOG("%@ got event report %@", self, value); + dispatch_async(self.queue, ^{ + // OnEventReport + [self _handleEventReport:value]; + }); + }, + ^(NSError * error) { + MTR_LOG_ERROR("%@ got subscription error %@", self, error); + dispatch_async(self.queue, ^{ + // OnError + [self _handleSubscriptionError:error]; + }); + }, + ^(NSError * error, NSNumber * resubscriptionDelayMs) { + MTR_LOG_ERROR("%@ got resubscription error %@ delay %@", self, error, resubscriptionDelayMs); + dispatch_async(self.queue, ^{ + // OnResubscriptionNeeded + [self _handleResubscriptionNeededWithDelay:resubscriptionDelayMs]; + }); + }, + ^(void) { + MTR_LOG("%@ got subscription established", self); + dispatch_async(self.queue, ^{ + // OnSubscriptionEstablished + [self _handleSubscriptionEstablished]; + }); + }, + ^(void) { + MTR_LOG("%@ got subscription done", self); + // Drop our pointer to the ReadClient immediately, since + // it's about to be destroyed and we don't want to be + // holding a dangling pointer. + std::lock_guard lock(self->_lock); + self->_currentReadClient = nullptr; + self->_currentSubscriptionCallback = nullptr; + + dispatch_async(self.queue, ^{ + // OnDone + [self _handleSubscriptionReset:nil]; + }); + }, + ^(void) { + MTR_LOG("%@ got unsolicited message from publisher", self); + dispatch_async(self.queue, ^{ + // OnUnsolicitedMessageFromPublisher + [self _handleUnsolicitedMessageFromPublisher]; + }); + }, + ^(void) { + MTR_LOG("%@ got report begin", self); + dispatch_async(self.queue, ^{ + [self _handleReportBegin]; + }); + }, + ^(void) { + MTR_LOG("%@ got report end", self); + dispatch_async(self.queue, ^{ + [self _handleReportEnd]; + }); + }); + + // Set up a cluster state cache. We just want this for the logic it has for + // tracking data versions and event numbers so we minimize the amount of data we + // request on resubscribes, so tell it not to store data. + auto clusterStateCache = std::make_unique(*callback.get(), + /* highestReceivedEventNumber = */ NullOptional, + /* cacheData = */ false); + auto readClient = std::make_unique(InteractionModelEngine::GetInstance(), exchangeManager, + clusterStateCache->GetBufferedCallback(), ReadClient::InteractionType::Subscribe); + + // Wildcard endpoint, cluster, attribute, event. + auto attributePath = std::make_unique(); + auto eventPath = std::make_unique(); + // We want to get event reports at the minInterval, not the maxInterval. + eventPath->mIsUrgentEvent = true; + ReadPrepareParams readParams(session.Value()); + + readParams.mMinIntervalFloorSeconds = 0; + // Select a max interval based on the device's claimed idle sleep interval. + auto idleSleepInterval = std::chrono::duration_cast( + session.Value()->GetRemoteMRPConfig().mIdleRetransTimeout); + + auto maxIntervalCeilingMin = System::Clock::Seconds32(MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MIN); + if (idleSleepInterval < maxIntervalCeilingMin) { + idleSleepInterval = maxIntervalCeilingMin; + } + + auto maxIntervalCeilingMax = System::Clock::Seconds32(MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MAX); + if (idleSleepInterval > maxIntervalCeilingMax) { + idleSleepInterval = maxIntervalCeilingMax; + } +#ifdef DEBUG + if (maxIntervalOverride.HasValue()) { + idleSleepInterval = maxIntervalOverride.Value(); + } +#endif + readParams.mMaxIntervalCeilingSeconds = static_cast(idleSleepInterval.count()); + + readParams.mpAttributePathParamsList = attributePath.get(); + readParams.mAttributePathParamsListSize = 1; + readParams.mpEventPathParamsList = eventPath.get(); + readParams.mEventPathParamsListSize = 1; + readParams.mKeepSubscriptions = true; + readParams.mIsFabricFiltered = false; + + // Subscribe with data version filter list from our cache. + size_t dataVersionFilterListSize = 0; + DataVersionFilter * dataVersionFilterList; + [self _createDataVersionFilterListFromDictionary:[self _getCachedDataVersions] dataVersionFilterList:&dataVersionFilterList count:&dataVersionFilterListSize]; + + readParams.mDataVersionFilterListSize = dataVersionFilterListSize; + readParams.mpDataVersionFilterList = dataVersionFilterList; + attributePath.release(); + eventPath.release(); + + // TODO: Change from local filter list generation to rehydrating ClusterStateCache to take advantage of existing filter list sorting algorithm + + // SendAutoResubscribeRequest cleans up the params, even on failure. + CHIP_ERROR err = readClient->SendAutoResubscribeRequest(std::move(readParams)); + if (err != CHIP_NO_ERROR) { + NSError * error = [MTRError errorForCHIPErrorCode:err logContext:self]; + MTR_LOG_ERROR("%@ SendAutoResubscribeRequest error %@", self, error); + dispatch_async(self.queue, ^{ + [self _handleSubscriptionError:error]; + [self _handleSubscriptionReset:nil]; + }); + + return; + } + + MTR_LOG("%@ Subscribe with data version list size %lu", self, static_cast(dataVersionFilterListSize)); + + // Callback and ClusterStateCache and ReadClient will be deleted + // when OnDone is called. + os_unfair_lock_lock(&self->_lock); + self->_currentReadClient = readClient.get(); + self->_currentSubscriptionCallback = callback.get(); + os_unfair_lock_unlock(&self->_lock); + callback->AdoptReadClient(std::move(readClient)); + callback->AdoptClusterStateCache(std::move(clusterStateCache)); + callback.release(); + }]; + + // Set up connectivity monitoring in case network becomes routable after any part of the subscription process goes into backoff retries. + [self _setupConnectivityMonitoring]; +} + +#ifdef DEBUG +- (NSUInteger)unitTestAttributesReportedSinceLastCheck +{ + NSUInteger attributesReportedSinceLastCheck = _unitTestAttributesReportedSinceLastCheck; + _unitTestAttributesReportedSinceLastCheck = 0; + return attributesReportedSinceLastCheck; +} + +- (NSUInteger)unitTestNonnullDelegateCount +{ + std::lock_guard lock(self->_lock); + + NSUInteger nonnullDelegateCount = 0; + for (MTRDeviceDelegateInfo_ConcreteCopy * delegateInfo in _delegates) { + if (delegateInfo.delegate) { + nonnullDelegateCount++; + } + } + + return nonnullDelegateCount; +} +#endif + +#pragma mark Device Interactions + +// Helper function to determine whether an attribute has "Changes Omitted" quality, which indicates that past the priming report in +// a subscription, this attribute is not expected to be reported when its value changes +// * TODO: xml+codegen version to replace this hardcoded list. +static BOOL AttributeHasChangesOmittedQuality(MTRAttributePath * attributePath) +{ + switch (attributePath.cluster.unsignedLongValue) { + case MTRClusterEthernetNetworkDiagnosticsID: + switch (attributePath.attribute.unsignedLongValue) { + case MTRClusterEthernetNetworkDiagnosticsAttributePacketRxCountID: + case MTRClusterEthernetNetworkDiagnosticsAttributePacketTxCountID: + case MTRClusterEthernetNetworkDiagnosticsAttributeTxErrCountID: + case MTRClusterEthernetNetworkDiagnosticsAttributeCollisionCountID: + case MTRClusterEthernetNetworkDiagnosticsAttributeOverrunCountID: + case MTRClusterEthernetNetworkDiagnosticsAttributeCarrierDetectID: + case MTRClusterEthernetNetworkDiagnosticsAttributeTimeSinceResetID: + return YES; + default: + return NO; + } + case MTRClusterGeneralDiagnosticsID: + switch (attributePath.attribute.unsignedLongValue) { + case MTRClusterGeneralDiagnosticsAttributeUpTimeID: + case MTRClusterGeneralDiagnosticsAttributeTotalOperationalHoursID: + return YES; + default: + return NO; + } + case MTRClusterThreadNetworkDiagnosticsID: + switch (attributePath.attribute.unsignedLongValue) { + case MTRClusterThreadNetworkDiagnosticsAttributeOverrunCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeDetachedRoleCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeChildRoleCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRouterRoleCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeLeaderRoleCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeAttachAttemptCountID: + case MTRClusterThreadNetworkDiagnosticsAttributePartitionIdChangeCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeBetterPartitionAttachAttemptCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeParentChangeCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxTotalCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxUnicastCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxBroadcastCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxAckRequestedCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxAckedCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxNoAckRequestedCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxDataCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxDataPollCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxBeaconCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxBeaconRequestCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxOtherCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxRetryCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxDirectMaxRetryExpiryCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxIndirectMaxRetryExpiryCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxErrCcaCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxErrAbortCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeTxErrBusyChannelCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxTotalCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxUnicastCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxBroadcastCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxDataCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxDataPollCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxBeaconCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxBeaconRequestCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxOtherCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxAddressFilteredCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxDestAddrFilteredCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxDuplicatedCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxErrNoFrameCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxErrUnknownNeighborCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxErrInvalidSrcAddrCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxErrSecCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxErrFcsCountID: + case MTRClusterThreadNetworkDiagnosticsAttributeRxErrOtherCountID: + return YES; + default: + return NO; + } + case MTRClusterWiFiNetworkDiagnosticsID: + switch (attributePath.attribute.unsignedLongValue) { + case MTRClusterWiFiNetworkDiagnosticsAttributeRssiID: + case MTRClusterWiFiNetworkDiagnosticsAttributeBeaconLostCountID: + case MTRClusterWiFiNetworkDiagnosticsAttributeBeaconRxCountID: + case MTRClusterWiFiNetworkDiagnosticsAttributePacketMulticastRxCountID: + case MTRClusterWiFiNetworkDiagnosticsAttributePacketMulticastTxCountID: + case MTRClusterWiFiNetworkDiagnosticsAttributePacketUnicastRxCountID: + case MTRClusterWiFiNetworkDiagnosticsAttributePacketUnicastTxCountID: + case MTRClusterWiFiNetworkDiagnosticsAttributeCurrentMaxRateID: + case MTRClusterWiFiNetworkDiagnosticsAttributeOverrunCountID: + return YES; + default: + return NO; + } + case MTRClusterOperationalCredentialsID: + switch (attributePath.attribute.unsignedLongValue) { + case MTRClusterOperationalCredentialsAttributeNOCsID: + case MTRClusterOperationalCredentialsAttributeTrustedRootCertificatesID: + return YES; + default: + return NO; + } + case MTRClusterPowerSourceID: + switch (attributePath.attribute.unsignedLongValue) { + case MTRClusterPowerSourceAttributeWiredAssessedInputVoltageID: + case MTRClusterPowerSourceAttributeWiredAssessedInputFrequencyID: + case MTRClusterPowerSourceAttributeWiredAssessedCurrentID: + case MTRClusterPowerSourceAttributeBatVoltageID: + case MTRClusterPowerSourceAttributeBatPercentRemainingID: + case MTRClusterPowerSourceAttributeBatTimeRemainingID: + case MTRClusterPowerSourceAttributeBatTimeToFullChargeID: + case MTRClusterPowerSourceAttributeBatChargingCurrentID: + return YES; + default: + return NO; + } + case MTRClusterTimeSynchronizationID: + switch (attributePath.attribute.unsignedLongValue) { + case MTRClusterTimeSynchronizationAttributeUTCTimeID: + case MTRClusterTimeSynchronizationAttributeLocalTimeID: + return YES; + default: + return NO; + } + default: + return NO; + } +} + +- (NSDictionary * _Nullable)readAttributeWithEndpointID:(NSNumber *)endpointID + clusterID:(NSNumber *)clusterID + attributeID:(NSNumber *)attributeID + params:(MTRReadParams * _Nullable)params +{ + MTRAttributePath * attributePath = [MTRAttributePath attributePathWithEndpointID:endpointID + clusterID:clusterID + attributeID:attributeID]; + + BOOL attributeIsSpecified = MTRAttributeIsSpecified(clusterID.unsignedIntValue, attributeID.unsignedIntValue); + BOOL hasChangesOmittedQuality; + if (attributeIsSpecified) { + hasChangesOmittedQuality = AttributeHasChangesOmittedQuality(attributePath); + } else { + if (params == nil) { + hasChangesOmittedQuality = NO; + } else { + hasChangesOmittedQuality = !params.assumeUnknownAttributesReportable; + } + } + + // Return current known / expected value right away + NSDictionary * attributeValueToReturn = [self _attributeValueDictionaryForAttributePath:attributePath]; + + // Send read request to device if any of the following are true: + // 1. Subscription not in a state we can expect reports + // 2. The attribute has the Changes Omitted quality, so we won't get reports for it. + // 3. The attribute is not in the spec, and the read params asks to assume + // an unknown attribute has the Changes Omitted quality. + if (![self _subscriptionAbleToReport] || hasChangesOmittedQuality) { + // Read requests container will be a mutable array of items, each being an array containing: + // [attribute request path, params] + // Batching handler should only coalesce when params are equal. + + // For this single read API there's only 1 array item. Use NSNull to stand in for nil params for easy comparison. + MTRAttributeRequestPath * readRequestPath = [MTRAttributeRequestPath requestPathWithEndpointID:endpointID + clusterID:clusterID + attributeID:attributeID]; + NSArray * readRequestData = @[ readRequestPath, params ?: [NSNull null] ]; + + // But first, check if a duplicate read request is already queued and return + if ([_asyncWorkQueue hasDuplicateForTypeID:MTRDeviceWorkItemDuplicateReadTypeID workItemData:readRequestData]) { + return attributeValueToReturn; + } + + NSMutableArray * readRequests = [NSMutableArray arrayWithObject:readRequestData]; + + // Create work item, set ready handler to perform task, then enqueue the work + MTRAsyncWorkItem * workItem = [[MTRAsyncWorkItem alloc] initWithQueue:self.queue]; + uint64_t workItemID = workItem.uniqueID; // capture only the ID, not the work item + NSNumber * nodeID = [self nodeID]; + + [workItem setBatchingID:MTRDeviceWorkItemBatchingReadID data:readRequests handler:^(id opaqueDataCurrent, id opaqueDataNext) { + mtr_hide(self); // don't capture self accidentally + NSMutableArray * readRequestsCurrent = opaqueDataCurrent; + NSMutableArray * readRequestsNext = opaqueDataNext; + + MTRBatchingOutcome outcome = MTRNotBatched; + while (readRequestsNext.count) { + // Can only read up to 9 paths at a time, per spec + if (readRequestsCurrent.count >= 9) { + MTR_LOG("Batching read attribute work item [%llu]: cannot add more work, item is full [0x%016llX:%@:0x%llx:0x%llx]", workItemID, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue); + return outcome; + } + + // if params don't match then they cannot be merged + if (![readRequestsNext[0][MTRDeviceReadRequestFieldParamsIndex] + isEqual:readRequestsCurrent[0][MTRDeviceReadRequestFieldParamsIndex]]) { + MTR_LOG("Batching read attribute work item [%llu]: cannot add more work, parameter mismatch [0x%016llX:%@:0x%llx:0x%llx]", workItemID, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue); + return outcome; + } + + // merge the next item's first request into the current item's list + auto readItem = readRequestsNext.firstObject; + [readRequestsNext removeObjectAtIndex:0]; + [readRequestsCurrent addObject:readItem]; + MTR_LOG("Batching read attribute work item [%llu]: added %@ (now %lu requests total) [0x%016llX:%@:0x%llx:0x%llx]", + workItemID, readItem, static_cast(readRequestsCurrent.count), nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue); + outcome = MTRBatchedPartially; + } + NSCAssert(readRequestsNext.count == 0, @"should have batched everything or returned early"); + return MTRBatchedFully; + }]; + [workItem setDuplicateTypeID:MTRDeviceWorkItemDuplicateReadTypeID handler:^(id opaqueItemData, BOOL * isDuplicate, BOOL * stop) { + mtr_hide(self); // don't capture self accidentally + for (NSArray * readItem in readRequests) { + if ([readItem isEqual:opaqueItemData]) { + MTR_LOG("Read attribute work item [%llu] report duplicate %@ [0x%016llX:%@:0x%llx:0x%llx]", workItemID, readItem, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue); + *isDuplicate = YES; + *stop = YES; + return; + } + } + *stop = NO; + }]; + [workItem setReadyHandler:^(MTRDevice_Concrete * self, NSInteger retryCount, MTRAsyncWorkCompletionBlock completion) { + // Sanity check + if (readRequests.count == 0) { + MTR_LOG_ERROR("Read attribute work item [%llu] contained no read requests", workItemID); + completion(MTRAsyncWorkComplete); + return; + } + + // Build the attribute paths from the read requests + NSMutableArray * attributePaths = [NSMutableArray array]; + for (NSArray * readItem in readRequests) { + NSAssert(readItem.count == 2, @"invalid read attribute item"); + [attributePaths addObject:readItem[MTRDeviceReadRequestFieldPathIndex]]; + } + // If param is the NSNull stand-in, then just use nil + id readParamObject = readRequests[0][MTRDeviceReadRequestFieldParamsIndex]; + MTRReadParams * readParams = (![readParamObject isEqual:[NSNull null]]) ? readParamObject : nil; + + MTRBaseDevice * baseDevice = [self newBaseDevice]; + [baseDevice + readAttributePaths:attributePaths + eventPaths:nil + params:readParams + includeDataVersion:YES + queue:self.queue + completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { + if (values) { + // Since the format is the same data-value dictionary, this looks like an + // attribute report + MTR_LOG("Read attribute work item [%llu] result: %@ [0x%016llX:%@:0x%llX:0x%llX]", workItemID, values, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue); + [self _handleAttributeReport:values fromSubscription:NO]; + } + + // TODO: better retry logic + if (error && (retryCount < 2)) { + MTR_LOG_ERROR("Read attribute work item [%llu] failed (will retry): %@ [0x%016llX:%@:0x%llx:0x%llx]", workItemID, error, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue); + completion(MTRAsyncWorkNeedsRetry); + } else { + if (error) { + MTR_LOG("Read attribute work item [%llu] failed (giving up): %@ [0x%016llX:%@:0x%llx:0x%llx]", workItemID, error, nodeID.unsignedLongLongValue, endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue); + } + completion(MTRAsyncWorkComplete); + } + }]; + }]; + [_asyncWorkQueue enqueueWorkItem:workItem descriptionWithFormat:@"read %@ 0x%llx 0x%llx", endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue]; + } else { + [self _readThroughSkipped]; + } + + return attributeValueToReturn; +} + +- (void)writeAttributeWithEndpointID:(NSNumber *)endpointID + clusterID:(NSNumber *)clusterID + attributeID:(NSNumber *)attributeID + value:(id)value + expectedValueInterval:(NSNumber *)expectedValueInterval + timedWriteTimeout:(NSNumber * _Nullable)timeout +{ + if (timeout) { + timeout = MTRClampedNumber(timeout, @(1), @(UINT16_MAX)); + } + expectedValueInterval = MTRClampedNumber(expectedValueInterval, @(1), @(UINT32_MAX)); + MTRAttributePath * attributePath = [MTRAttributePath attributePathWithEndpointID:endpointID + clusterID:clusterID + + attributeID:attributeID]; + + __block BOOL useValueAsExpectedValue = YES; +#ifdef DEBUG + os_unfair_lock_lock(&self->_lock); + [self _callFirstDelegateSynchronouslyWithBlock:^(id delegate) { + if ([delegate respondsToSelector:@selector(unitTestShouldSkipExpectedValuesForWrite:)]) { + useValueAsExpectedValue = ![delegate unitTestShouldSkipExpectedValuesForWrite:self]; + } + }]; + os_unfair_lock_unlock(&self->_lock); +#endif + + uint64_t expectedValueID = 0; + if (useValueAsExpectedValue) { + // Commit change into expected value cache + NSDictionary * newExpectedValueDictionary = @{ MTRAttributePathKey : attributePath, MTRDataKey : value }; + [self setExpectedValues:@[ newExpectedValueDictionary ] + expectedValueInterval:expectedValueInterval + expectedValueID:&expectedValueID]; + } + + MTRAsyncWorkItem * workItem = [[MTRAsyncWorkItem alloc] initWithQueue:self.queue]; + uint64_t workItemID = workItem.uniqueID; // capture only the ID, not the work item + NSNumber * nodeID = _nodeID; + + // Write request data is an array of items (for now always length 1). Each + // item is an array containing: + // + // [ attribute path, value, timedWriteTimeout, expectedValueID ] + // + // where expectedValueID is stored as NSNumber and NSNull represents nil timeouts + auto * writeData = @[ attributePath, [value copy], timeout ?: [NSNull null], @(expectedValueID) ]; + + NSMutableArray * writeRequests = [NSMutableArray arrayWithObject:writeData]; + + [workItem setBatchingID:MTRDeviceWorkItemBatchingWriteID data:writeRequests handler:^(id opaqueDataCurrent, id opaqueDataNext) { + mtr_hide(self); // don't capture self accidentally + NSMutableArray * writeRequestsCurrent = opaqueDataCurrent; + NSMutableArray * writeRequestsNext = opaqueDataNext; + + if (writeRequestsCurrent.count != 1) { + // Very unexpected! + MTR_LOG_ERROR("Batching write attribute work item [%llu]: Unexpected write request count %lu", workItemID, static_cast(writeRequestsCurrent.count)); + return MTRNotBatched; + } + + MTRBatchingOutcome outcome = MTRNotBatched; + while (writeRequestsNext.count) { + // If paths don't match, we cannot replace the earlier write + // with the later one. + if (![writeRequestsNext[0][MTRDeviceWriteRequestFieldPathIndex] + isEqual:writeRequestsCurrent[0][MTRDeviceWriteRequestFieldPathIndex]]) { + MTR_LOG("Batching write attribute work item [%llu]: cannot replace with next work item due to path mismatch", workItemID); + return outcome; + } + + // Replace our one request with the first one from the next item. + auto writeItem = writeRequestsNext.firstObject; + [writeRequestsNext removeObjectAtIndex:0]; + [writeRequestsCurrent replaceObjectAtIndex:0 withObject:writeItem]; + MTR_LOG("Batching write attribute work item [%llu]: replaced with new write value %@ [0x%016llX]", + workItemID, writeItem, nodeID.unsignedLongLongValue); + outcome = MTRBatchedPartially; + } + NSCAssert(writeRequestsNext.count == 0, @"should have batched everything or returned early"); + return MTRBatchedFully; + }]; + // The write operation will install a duplicate check handler, to return NO for "isDuplicate". Since a write operation may + // change values, only read requests after this should be considered for duplicate requests. + [workItem setDuplicateTypeID:MTRDeviceWorkItemDuplicateReadTypeID handler:^(id opaqueItemData, BOOL * isDuplicate, BOOL * stop) { + *isDuplicate = NO; + *stop = YES; + }]; + [workItem setReadyHandler:^(MTRDevice_Concrete * self, NSInteger retryCount, MTRAsyncWorkCompletionBlock completion) { + MTRBaseDevice * baseDevice = [self newBaseDevice]; + // Make sure to use writeRequests here, because that's what our batching + // handler will modify as needed. + NSCAssert(writeRequests.count == 1, @"Incorrect number of write requests: %lu", static_cast(writeRequests.count)); + + auto * request = writeRequests[0]; + MTRAttributePath * path = request[MTRDeviceWriteRequestFieldPathIndex]; + + id timedWriteTimeout = request[MTRDeviceWriteRequestFieldTimeoutIndex]; + if (timedWriteTimeout == [NSNull null]) { + timedWriteTimeout = nil; + } + + [baseDevice + writeAttributeWithEndpointID:path.endpoint + clusterID:path.cluster + attributeID:path.attribute + value:request[MTRDeviceWriteRequestFieldValueIndex] + timedWriteTimeout:timedWriteTimeout + queue:self.queue + completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { + if (error) { + MTR_LOG_ERROR("Write attribute work item [%llu] failed: %@", workItemID, error); + if (useValueAsExpectedValue) { + NSNumber * expectedValueID = request[MTRDeviceWriteRequestFieldExpectedValueIDIndex]; + [self removeExpectedValueForAttributePath:attributePath expectedValueID:expectedValueID.unsignedLongLongValue]; + } + } + completion(MTRAsyncWorkComplete); + }]; + }]; + [_asyncWorkQueue enqueueWorkItem:workItem descriptionWithFormat:@"write %@ 0x%llx 0x%llx", endpointID, clusterID.unsignedLongLongValue, attributeID.unsignedLongLongValue]; +} + +- (void)invokeCommandWithEndpointID:(NSNumber *)endpointID + clusterID:(NSNumber *)clusterID + commandID:(NSNumber *)commandID + commandFields:(NSDictionary * _Nullable)commandFields + expectedValues:(NSArray *> * _Nullable)expectedValues + expectedValueInterval:(NSNumber * _Nullable)expectedValueInterval + queue:(dispatch_queue_t)queue + completion:(MTRDeviceResponseHandler)completion +{ + if (commandFields == nil) { + commandFields = @{ + MTRTypeKey : MTRStructureValueType, + MTRValueKey : @[], + }; + } + + [self invokeCommandWithEndpointID:endpointID + clusterID:clusterID + commandID:commandID + commandFields:commandFields + expectedValues:expectedValues + expectedValueInterval:expectedValueInterval + timedInvokeTimeout:nil + queue:queue + completion:completion]; +} + +- (void)invokeCommandWithEndpointID:(NSNumber *)endpointID + clusterID:(NSNumber *)clusterID + commandID:(NSNumber *)commandID + commandFields:(id)commandFields + expectedValues:(NSArray *> * _Nullable)expectedValues + expectedValueInterval:(NSNumber * _Nullable)expectedValueInterval + timedInvokeTimeout:(NSNumber * _Nullable)timeout + queue:(dispatch_queue_t)queue + completion:(MTRDeviceResponseHandler)completion +{ + // We don't have a way to communicate a non-default invoke timeout + // here for now. + // TODO: https://github.com/project-chip/connectedhomeip/issues/24563 + + [self _invokeCommandWithEndpointID:endpointID + clusterID:clusterID + commandID:commandID + commandFields:commandFields + expectedValues:expectedValues + expectedValueInterval:expectedValueInterval + timedInvokeTimeout:timeout + serverSideProcessingTimeout:nil + queue:queue + completion:completion]; +} + +- (void)_invokeCommandWithEndpointID:(NSNumber *)endpointID + clusterID:(NSNumber *)clusterID + commandID:(NSNumber *)commandID + commandFields:(id)commandFields + expectedValues:(NSArray *> * _Nullable)expectedValues + expectedValueInterval:(NSNumber * _Nullable)expectedValueInterval + timedInvokeTimeout:(NSNumber * _Nullable)timeout + serverSideProcessingTimeout:(NSNumber * _Nullable)serverSideProcessingTimeout + queue:(dispatch_queue_t)queue + completion:(MTRDeviceResponseHandler)completion +{ + if (!expectedValueInterval || ([expectedValueInterval compare:@(0)] == NSOrderedAscending)) { + expectedValues = nil; + } else { + expectedValueInterval = MTRClampedNumber(expectedValueInterval, @(1), @(UINT32_MAX)); + } + + serverSideProcessingTimeout = [serverSideProcessingTimeout copy]; + timeout = [timeout copy]; + + if (timeout == nil && MTRCommandNeedsTimedInvoke(clusterID, commandID)) { + timeout = @(MTR_DEFAULT_TIMED_INTERACTION_TIMEOUT_MS); + } + + NSDate * cutoffTime; + if (timeout) { + cutoffTime = [NSDate dateWithTimeIntervalSinceNow:(timeout.doubleValue / 1000)]; + } + + uint64_t expectedValueID = 0; + NSMutableArray * attributePaths = nil; + if (expectedValues) { + [self setExpectedValues:expectedValues expectedValueInterval:expectedValueInterval expectedValueID:&expectedValueID]; + attributePaths = [NSMutableArray array]; + for (NSDictionary * expectedValue in expectedValues) { + [attributePaths addObject:expectedValue[MTRAttributePathKey]]; + } + } + MTRAsyncWorkItem * workItem = [[MTRAsyncWorkItem alloc] initWithQueue:self.queue]; + uint64_t workItemID = workItem.uniqueID; // capture only the ID, not the work item + // The command operation will install a duplicate check handler, to return NO for "isDuplicate". Since a command operation may + // change values, only read requests after this should be considered for duplicate requests. + [workItem setDuplicateTypeID:MTRDeviceWorkItemDuplicateReadTypeID handler:^(id opaqueItemData, BOOL * isDuplicate, BOOL * stop) { + *isDuplicate = NO; + *stop = YES; + }]; + [workItem setReadyHandler:^(MTRDevice_Concrete * self, NSInteger retryCount, MTRAsyncWorkCompletionBlock workCompletion) { + auto workDone = ^(NSArray *> * _Nullable values, NSError * _Nullable error) { + dispatch_async(queue, ^{ + completion(values, error); + }); + if (error && expectedValues) { + [self removeExpectedValuesForAttributePaths:attributePaths expectedValueID:expectedValueID]; + } + workCompletion(MTRAsyncWorkComplete); + }; + + NSNumber * timedInvokeTimeout = nil; + if (timeout) { + auto * now = [NSDate now]; + if ([now compare:cutoffTime] == NSOrderedDescending) { + // Our timed invoke timeout has expired already. Command + // was queued for too long. Do not send it out. + workDone(nil, [MTRError errorForIMStatusCode:Status::Timeout]); + return; + } + + // Recompute the actual timeout left, accounting for time spent + // in our queuing and retries. + timedInvokeTimeout = @([cutoffTime timeIntervalSinceDate:now] * 1000); + } + MTRBaseDevice * baseDevice = [self newBaseDevice]; + [baseDevice + _invokeCommandWithEndpointID:endpointID + clusterID:clusterID + commandID:commandID + commandFields:commandFields + timedInvokeTimeout:timedInvokeTimeout + serverSideProcessingTimeout:serverSideProcessingTimeout + queue:self.queue + completion:^(NSArray *> * _Nullable values, NSError * _Nullable error) { + // Log the data at the INFO level (not usually persisted permanently), + // but make sure we log the work completion at the DEFAULT level. + MTR_LOG("Invoke work item [%llu] received command response: %@ error: %@", workItemID, values, error); + // TODO: This 5-retry cap is very arbitrary. + // TODO: Should there be some sort of backoff here? + if (error != nil && error.domain == MTRInteractionErrorDomain && error.code == MTRInteractionErrorCodeBusy && retryCount < 5) { + workCompletion(MTRAsyncWorkNeedsRetry); + return; + } + + workDone(values, error); + }]; + }]; + [_asyncWorkQueue enqueueWorkItem:workItem descriptionWithFormat:@"invoke %@ 0x%llx 0x%llx", endpointID, clusterID.unsignedLongLongValue, commandID.unsignedLongLongValue]; +} + +- (void)_invokeKnownCommandWithEndpointID:(NSNumber *)endpointID + clusterID:(NSNumber *)clusterID + commandID:(NSNumber *)commandID + commandPayload:(id)commandPayload + expectedValues:(NSArray *> * _Nullable)expectedValues + expectedValueInterval:(NSNumber * _Nullable)expectedValueInterval + timedInvokeTimeout:(NSNumber * _Nullable)timeout + serverSideProcessingTimeout:(NSNumber * _Nullable)serverSideProcessingTimeout + responseClass:(Class _Nullable)responseClass + queue:(dispatch_queue_t)queue + completion:(void (^)(id _Nullable response, NSError * _Nullable error))completion +{ + if (![commandPayload respondsToSelector:@selector(_encodeAsDataValue:)]) { + dispatch_async(queue, ^{ + completion(nil, [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_ARGUMENT]); + }); + return; + } + + NSError * encodingError; + auto * commandFields = [commandPayload _encodeAsDataValue:&encodingError]; + if (commandFields == nil) { + dispatch_async(queue, ^{ + completion(nil, encodingError); + }); + return; + } + + auto responseHandler = ^(NSArray *> * _Nullable values, NSError * _Nullable error) { + id _Nullable response = nil; + if (error == nil) { + if (values.count != 1) { + error = [NSError errorWithDomain:MTRErrorDomain code:MTRErrorCodeSchemaMismatch userInfo:nil]; + } else if (responseClass != nil) { + response = [[responseClass alloc] initWithResponseValue:values[0] error:&error]; + } + } + completion(response, error); + }; + + [self _invokeCommandWithEndpointID:endpointID + clusterID:clusterID + commandID:commandID + commandFields:commandFields + expectedValues:expectedValues + expectedValueInterval:expectedValueInterval + timedInvokeTimeout:timeout + serverSideProcessingTimeout:serverSideProcessingTimeout + queue:queue + completion:responseHandler]; +} + +- (void)openCommissioningWindowWithSetupPasscode:(NSNumber *)setupPasscode + discriminator:(NSNumber *)discriminator + duration:(NSNumber *)duration + queue:(dispatch_queue_t)queue + completion:(MTRDeviceOpenCommissioningWindowHandler)completion +{ + auto * baseDevice = [self newBaseDevice]; + [baseDevice openCommissioningWindowWithSetupPasscode:setupPasscode + discriminator:discriminator + duration:duration + queue:queue + completion:completion]; +} + +- (void)openCommissioningWindowWithDiscriminator:(NSNumber *)discriminator + duration:(NSNumber *)duration + queue:(dispatch_queue_t)queue + completion:(MTRDeviceOpenCommissioningWindowHandler)completion +{ + auto * baseDevice = [self newBaseDevice]; + [baseDevice openCommissioningWindowWithDiscriminator:discriminator duration:duration queue:queue completion:completion]; +} + +- (void)downloadLogOfType:(MTRDiagnosticLogType)type + timeout:(NSTimeInterval)timeout + queue:(dispatch_queue_t)queue + completion:(void (^)(NSURL * _Nullable url, NSError * _Nullable error))completion +{ + auto * baseDevice = [self newBaseDevice]; + [baseDevice downloadLogOfType:type + timeout:timeout + queue:queue + completion:completion]; +} + +#pragma mark - Cache management + +// assume lock is held +- (void)_checkExpiredExpectedValues +{ + os_unfair_lock_assert_owner(&self->_lock); + + // find expired attributes, and calculate next timer fire date + NSDate * now = [NSDate date]; + NSDate * nextExpirationDate = nil; + // Set of NSArray with 2 elements [path, value] - this is used in this method only + NSMutableSet * attributeInfoToRemove = [NSMutableSet set]; + for (MTRAttributePath * attributePath in _expectedValueCache) { + NSArray * expectedValue = _expectedValueCache[attributePath]; + NSDate * attributeExpirationDate = expectedValue[MTRDeviceExpectedValueFieldExpirationTimeIndex]; + if (expectedValue) { + if ([now compare:attributeExpirationDate] == NSOrderedDescending) { + // expired - save [path, values] pair to attributeToRemove + [attributeInfoToRemove addObject:@[ attributePath, expectedValue[MTRDeviceExpectedValueFieldValueIndex] ]]; + } else { + // get the next expiration date + if (!nextExpirationDate || [nextExpirationDate compare:attributeExpirationDate] == NSOrderedDescending) { + nextExpirationDate = attributeExpirationDate; + } + } + } + } + + // remove from expected value cache and report attributes as needed + NSMutableArray * attributesToReport = [NSMutableArray array]; + NSMutableArray * attributePathsToReport = [NSMutableArray array]; + for (NSArray * attributeInfo in attributeInfoToRemove) { + // compare with known value and mark for report if different + MTRAttributePath * attributePath = attributeInfo[0]; + NSDictionary * attributeDataValue = attributeInfo[1]; + NSDictionary * cachedAttributeDataValue = [self _cachedAttributeValueForPath:attributePath]; + if (cachedAttributeDataValue + && ![self _attributeDataValue:attributeDataValue isEqualToDataValue:cachedAttributeDataValue]) { + [attributesToReport addObject:@{ MTRAttributePathKey : attributePath, MTRDataKey : cachedAttributeDataValue, MTRPreviousDataKey : attributeDataValue }]; + [attributePathsToReport addObject:attributePath]; + } + + _expectedValueCache[attributePath] = nil; + } + + // log attribute paths + MTR_LOG("%@ report from expired expected values %@", self, attributePathsToReport); + [self _reportAttributes:attributesToReport]; + +// Have a reasonable minimum wait time for expiration timers +#define MTR_DEVICE_EXPIRATION_CHECK_TIMER_MINIMUM_WAIT_TIME (0.1) + + if (nextExpirationDate && _expectedValueCache.count && !self.expirationCheckScheduled) { + NSTimeInterval waitTime = [nextExpirationDate timeIntervalSinceDate:now]; + if (waitTime < MTR_DEVICE_EXPIRATION_CHECK_TIMER_MINIMUM_WAIT_TIME) { + waitTime = MTR_DEVICE_EXPIRATION_CHECK_TIMER_MINIMUM_WAIT_TIME; + } + mtr_weakify(self); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t) (waitTime * NSEC_PER_SEC)), self.queue, ^{ + mtr_strongify(self); + [self _performScheduledExpirationCheck]; + }); + } +} + +- (void)_performScheduledExpirationCheck +{ + std::lock_guard lock(_lock); + + self.expirationCheckScheduled = NO; + [self _checkExpiredExpectedValues]; +} + +// Get attribute value dictionary for an attribute path from the right cache +- (NSDictionary *)_attributeValueDictionaryForAttributePath:(MTRAttributePath *)attributePath +{ + std::lock_guard lock(_lock); + + // First check expected value cache + NSArray * expectedValue = _expectedValueCache[attributePath]; + if (expectedValue) { + NSDate * now = [NSDate date]; + if ([now compare:expectedValue[MTRDeviceExpectedValueFieldExpirationTimeIndex]] == NSOrderedDescending) { + // expired - purge and fall through + _expectedValueCache[attributePath] = nil; + } else { + // not yet expired - return result + return expectedValue[MTRDeviceExpectedValueFieldValueIndex]; + } + } + + // Then check read cache + NSDictionary * cachedAttributeValue = [self _cachedAttributeValueForPath:attributePath]; + if (cachedAttributeValue) { + return cachedAttributeValue; + } else { + // TODO: when not found in cache, generated default values should be used + MTR_LOG("%@ _attributeValueDictionaryForAttributePath: could not find cached attribute values for attribute %@", self, + attributePath); + } + + return nil; +} + +- (BOOL)_attributeDataValue:(NSDictionary *)one isEqualToDataValue:(NSDictionary *)theOther +{ + // Sanity check for nil cases + if (!one && !theOther) { + MTR_LOG_ERROR("%@ attribute data-value comparison does not expect comparing two nil dictionaries", self); + return YES; + } + if (!one || !theOther) { + // Comparing against nil is expected, and should return NO quietly + return NO; + } + + // Attribute data-value dictionaries are equal if type and value are equal, and specifically, this should return true if values are both nil + return [one[MTRTypeKey] isEqual:theOther[MTRTypeKey]] && ((one[MTRValueKey] == theOther[MTRValueKey]) || [one[MTRValueKey] isEqual:theOther[MTRValueKey]]); +} + +// Utility to return data value dictionary without data version +- (NSDictionary *)_dataValueWithoutDataVersion:(NSDictionary *)attributeValue +{ + // Sanity check for nil - return the same input to fail gracefully + if (!attributeValue || !attributeValue[MTRTypeKey]) { + return attributeValue; + } + + if (attributeValue[MTRValueKey]) { + return @{ MTRTypeKey : attributeValue[MTRTypeKey], MTRValueKey : attributeValue[MTRValueKey] }; + } else { + return @{ MTRTypeKey : attributeValue[MTRTypeKey] }; + } +} + +// Update cluster data version and also note the change, so at onReportEnd it can be persisted +- (void)_noteDataVersion:(NSNumber *)dataVersion forClusterPath:(MTRClusterPath *)clusterPath +{ + os_unfair_lock_assert_owner(&self->_lock); + + BOOL dataVersionChanged = NO; + // Update data version used for subscription filtering + MTRDeviceClusterData * clusterData = [self _clusterDataForPath:clusterPath]; + if (!clusterData) { + clusterData = [[MTRDeviceClusterData alloc] initWithDataVersion:dataVersion attributes:nil]; + dataVersionChanged = YES; + } else if (![clusterData.dataVersion isEqualToNumber:dataVersion]) { + clusterData.dataVersion = dataVersion; + dataVersionChanged = YES; + } + + if (dataVersionChanged) { + if (_clusterDataToPersist == nil) { + _clusterDataToPersist = [NSMutableDictionary dictionary]; + } + _clusterDataToPersist[clusterPath] = clusterData; + } +} + +- (BOOL)_attributeAffectsDeviceConfiguration:(MTRAttributePath *)attributePath +{ + // Check for attributes in the descriptor cluster that affect device configuration. + if (attributePath.cluster.unsignedLongValue == MTRClusterIDTypeDescriptorID) { + switch (attributePath.attribute.unsignedLongValue) { + case MTRAttributeIDTypeClusterDescriptorAttributePartsListID: + case MTRAttributeIDTypeClusterDescriptorAttributeServerListID: + case MTRAttributeIDTypeClusterDescriptorAttributeDeviceTypeListID: { + return YES; + } + } + } + + // Check for global attributes that affect device configuration. + switch (attributePath.attribute.unsignedLongValue) { + case MTRAttributeIDTypeGlobalAttributeAcceptedCommandListID: + case MTRAttributeIDTypeGlobalAttributeAttributeListID: + case MTRAttributeIDTypeGlobalAttributeClusterRevisionID: + case MTRAttributeIDTypeGlobalAttributeFeatureMapID: + return YES; + } + return NO; +} + +- (void)_removeClusters:(NSSet *)clusterPathsToRemove + doRemoveFromDataStore:(BOOL)doRemoveFromDataStore +{ + os_unfair_lock_assert_owner(&self->_lock); + + [_persistedClusters minusSet:clusterPathsToRemove]; + + for (MTRClusterPath * path in clusterPathsToRemove) { + [_persistedClusterData removeObjectForKey:path]; + [_clusterDataToPersist removeObjectForKey:path]; + if (doRemoveFromDataStore) { + [self.deviceController.controllerDataStore clearStoredClusterDataForNodeID:self.nodeID endpointID:path.endpoint clusterID:path.cluster]; + } + } +} + +- (void)_removeAttributes:(NSSet *)attributes fromCluster:(MTRClusterPath *)clusterPath +{ + os_unfair_lock_assert_owner(&self->_lock); + + for (NSNumber * attribute in attributes) { + [self _removeCachedAttribute:attribute fromCluster:clusterPath]; + } + // Just clear out the NSCache entry for this cluster, so we'll load it from storage as needed. + [_persistedClusterData removeObjectForKey:clusterPath]; + [self.deviceController.controllerDataStore removeAttributes:attributes fromCluster:clusterPath forNodeID:self.nodeID]; +} + +- (void)_pruneEndpointsIn:(MTRDeviceDataValueDictionary)previousPartsListValue + missingFrom:(MTRDeviceDataValueDictionary)newPartsListValue +{ + // If the parts list changed and one or more endpoints were removed, remove all the + // clusters for all those endpoints from our data structures. + // Also remove those endpoints from the data store. + NSMutableSet * toBeRemovedEndpoints = [NSMutableSet setWithArray:[self arrayOfNumbersFromAttributeValue:previousPartsListValue]]; + NSSet * endpointsOnDevice = [NSSet setWithArray:[self arrayOfNumbersFromAttributeValue:newPartsListValue]]; + [toBeRemovedEndpoints minusSet:endpointsOnDevice]; + + for (NSNumber * endpoint in toBeRemovedEndpoints) { + NSMutableSet * clusterPathsToRemove = [[NSMutableSet alloc] init]; + for (MTRClusterPath * path in _persistedClusters) { + if ([path.endpoint isEqualToNumber:endpoint]) { + [clusterPathsToRemove addObject:path]; + } + } + [self _removeClusters:clusterPathsToRemove doRemoveFromDataStore:NO]; + [self.deviceController.controllerDataStore clearStoredClusterDataForNodeID:self.nodeID endpointID:endpoint]; + + [_deviceController asyncDispatchToMatterQueue:^{ + std::lock_guard lock(self->_lock); + if (self->_currentSubscriptionCallback) { + self->_currentSubscriptionCallback->ClearCachedAttributeState(static_cast(endpoint.unsignedLongLongValue)); + } + } errorHandler:nil]; + } +} + +- (void)_pruneClustersIn:(MTRDeviceDataValueDictionary)previousServerListValue + missingFrom:(MTRDeviceDataValueDictionary)newServerListValue + forEndpoint:(NSNumber *)endpointID +{ + // If the server list changed and clusters were removed, remove those clusters from our data structures. + // Also remove them from the data store. + NSMutableSet * toBeRemovedClusters = [NSMutableSet setWithArray:[self arrayOfNumbersFromAttributeValue:previousServerListValue]]; + NSSet * clustersStillOnEndpoint = [NSSet setWithArray:[self arrayOfNumbersFromAttributeValue:newServerListValue]]; + [toBeRemovedClusters minusSet:clustersStillOnEndpoint]; + + NSMutableSet * clusterPathsToRemove = [[NSMutableSet alloc] init]; + for (MTRClusterPath * path in _persistedClusters) { + if ([path.endpoint isEqualToNumber:endpointID] && [toBeRemovedClusters containsObject:path.cluster]) { + [clusterPathsToRemove addObject:path]; + } + } + [self _removeClusters:clusterPathsToRemove doRemoveFromDataStore:YES]; + + [_deviceController asyncDispatchToMatterQueue:^{ + std::lock_guard lock(self->_lock); + if (self->_currentSubscriptionCallback) { + for (NSNumber * cluster in toBeRemovedClusters) { + ConcreteClusterPath clusterPath(static_cast(endpointID.unsignedLongLongValue), + static_cast(cluster.unsignedLongLongValue)); + self->_currentSubscriptionCallback->ClearCachedAttributeState(clusterPath); + } + } + } errorHandler:nil]; +} + +- (void)_pruneAttributesIn:(MTRDeviceDataValueDictionary)previousAttributeListValue + missingFrom:(MTRDeviceDataValueDictionary)newAttributeListValue + forCluster:(MTRClusterPath *)clusterPath +{ + // If the attribute list changed and attributes were removed, remove the attributes from our + // data structures. + NSMutableSet * toBeRemovedAttributes = [NSMutableSet setWithArray:[self arrayOfNumbersFromAttributeValue:previousAttributeListValue]]; + NSSet * attributesStillInCluster = [NSSet setWithArray:[self arrayOfNumbersFromAttributeValue:newAttributeListValue]]; + + [toBeRemovedAttributes minusSet:attributesStillInCluster]; + [self _removeAttributes:toBeRemovedAttributes fromCluster:clusterPath]; + + [_deviceController asyncDispatchToMatterQueue:^{ + std::lock_guard lock(self->_lock); + if (self->_currentSubscriptionCallback) { + for (NSNumber * attribute in toBeRemovedAttributes) { + ConcreteAttributePath attributePath(static_cast(clusterPath.endpoint.unsignedLongLongValue), + static_cast(clusterPath.cluster.unsignedLongLongValue), + static_cast(attribute.unsignedLongLongValue)); + self->_currentSubscriptionCallback->ClearCachedAttributeState(attributePath); + } + } + } errorHandler:nil]; +} + +- (void)_pruneStoredDataForPath:(MTRAttributePath *)attributePath + missingFrom:(MTRDeviceDataValueDictionary)newAttributeDataValue +{ + os_unfair_lock_assert_owner(&self->_lock); + + if (![self _dataStoreExists] && !_clusterDataToPersist.count) { + MTR_LOG_DEBUG("%@ No data store to prune from", self); + return; + } + + // Check if parts list changed or server list changed for the descriptor cluster or the attribute list changed for a cluster. + // If yes, we might need to prune any deleted endpoints, clusters or attributes from the storage and persisted cluster data. + if (attributePath.cluster.unsignedLongValue == MTRClusterIDTypeDescriptorID) { + if (attributePath.attribute.unsignedLongValue == MTRAttributeIDTypeClusterDescriptorAttributePartsListID && [attributePath.endpoint isEqualToNumber:@(kRootEndpointId)]) { + [self _pruneEndpointsIn:[self _cachedAttributeValueForPath:attributePath] missingFrom:newAttributeDataValue]; + return; + } + + if (attributePath.attribute.unsignedLongValue == MTRAttributeIDTypeClusterDescriptorAttributeServerListID) { + [self _pruneClustersIn:[self _cachedAttributeValueForPath:attributePath] missingFrom:newAttributeDataValue forEndpoint:attributePath.endpoint]; + return; + } + } + + if (attributePath.attribute.unsignedLongValue == MTRAttributeIDTypeGlobalAttributeAttributeListID) { + [self _pruneAttributesIn:[self _cachedAttributeValueForPath:attributePath] missingFrom:newAttributeDataValue forCluster:[MTRClusterPath clusterPathWithEndpointID:attributePath.endpoint clusterID:attributePath.cluster]]; + } +} + +// assume lock is held +- (NSArray *)_getAttributesToReportWithReportedValues:(NSArray *> *)reportedAttributeValues fromSubscription:(BOOL)isFromSubscription +{ + os_unfair_lock_assert_owner(&self->_lock); + + NSMutableArray * attributesToReport = [NSMutableArray array]; + NSMutableArray * attributePathsToReport = [NSMutableArray array]; + for (NSDictionary * attributeResponseValue in reportedAttributeValues) { + MTRAttributePath * attributePath = attributeResponseValue[MTRAttributePathKey]; + NSDictionary * attributeDataValue = attributeResponseValue[MTRDataKey]; + NSError * attributeError = attributeResponseValue[MTRErrorKey]; + NSDictionary * previousValue; + + // sanity check either data value or error must exist + if (!attributeDataValue && !attributeError) { + MTR_LOG("%@ report %@ no data value or error: %@", self, attributePath, attributeResponseValue); + continue; + } + + // Additional signal to help mark events as being received during priming report in the event the device rebooted and we get a subscription resumption priming report without noticing it became unreachable first + if (_receivingReport && AttributeHasChangesOmittedQuality(attributePath)) { + _receivingPrimingReport = YES; + } + + // check if value is different than cache, and report if needed + BOOL shouldReportAttribute = NO; + + // if this is an error, report and purge cache + if (attributeError) { + shouldReportAttribute = YES; + previousValue = [self _cachedAttributeValueForPath:attributePath]; + MTR_LOG_ERROR("%@ report %@ error %@ purge expected value %@ read cache %@", self, attributePath, attributeError, + _expectedValueCache[attributePath], previousValue); + _expectedValueCache[attributePath] = nil; + // TODO: Is this clearing business really what we want? + [self _setCachedAttributeValue:nil forPath:attributePath fromSubscription:isFromSubscription]; + } else { + // First separate data version and restore data value to a form without data version + NSNumber * dataVersion = attributeDataValue[MTRDataVersionKey]; + MTRClusterPath * clusterPath = [MTRClusterPath clusterPathWithEndpointID:attributePath.endpoint clusterID:attributePath.cluster]; + if (dataVersion) { + // Remove data version from what we cache in memory + attributeDataValue = [self _dataValueWithoutDataVersion:attributeDataValue]; + } + + previousValue = [self _cachedAttributeValueForPath:attributePath]; +#ifdef DEBUG + __block BOOL readCacheValueChanged = ![self _attributeDataValue:attributeDataValue isEqualToDataValue:previousValue]; +#else + BOOL readCacheValueChanged = ![self _attributeDataValue:attributeDataValue isEqualToDataValue:previousValue]; +#endif + // Now that we have grabbed previousValue, update our cache with the attribute value. + if (readCacheValueChanged) { + if (dataVersion) { + [self _noteDataVersion:dataVersion forClusterPath:clusterPath]; + } + + [self _pruneStoredDataForPath:attributePath missingFrom:attributeDataValue]; + + if (!_deviceConfigurationChanged) { + _deviceConfigurationChanged = [self _attributeAffectsDeviceConfiguration:attributePath]; + if (_deviceConfigurationChanged) { + MTR_LOG("Device configuration changed due to changes in attribute %@", attributePath); + } + } + + [self _setCachedAttributeValue:attributeDataValue forPath:attributePath fromSubscription:isFromSubscription]; + } + +#ifdef DEBUG + // Unit test only code. + if (!readCacheValueChanged) { + [self _callFirstDelegateSynchronouslyWithBlock:^(id delegate) { + if ([delegate respondsToSelector:@selector(unitTestForceAttributeReportsIfMatchingCache:)]) { + readCacheValueChanged = [delegate unitTestForceAttributeReportsIfMatchingCache:self]; + } + }]; + } +#endif // DEBUG + + NSArray * expectedValue = _expectedValueCache[attributePath]; + + // Report the attribute if a read would get a changed value. This happens + // when our cached value changes and no expected value exists. + if (readCacheValueChanged && !expectedValue) { + shouldReportAttribute = YES; + } + + if (!shouldReportAttribute) { + // If an expected value exists, the attribute will not be reported at this time. + // When the expected value interval expires, the correct value will be reported, + // if needed. + if (expectedValue) { + MTR_LOG("%@ report %@ value filtered - expected value still present", self, attributePath); + } else { + MTR_LOG("%@ report %@ value filtered - same as read cache", self, attributePath); + } + } + + // If General Diagnostics UpTime attribute, update the estimated start time as needed. + if ((attributePath.cluster.unsignedLongValue == MTRClusterGeneralDiagnosticsID) + && (attributePath.attribute.unsignedLongValue == MTRClusterGeneralDiagnosticsAttributeUpTimeID)) { + // verify that the uptime is indeed the data type we want + if ([attributeDataValue[MTRTypeKey] isEqual:MTRUnsignedIntegerValueType]) { + NSNumber * upTimeNumber = attributeDataValue[MTRValueKey]; + NSTimeInterval upTime = upTimeNumber.unsignedLongLongValue; // UpTime unit is defined as seconds in the spec + NSDate * potentialSystemStartTime = [NSDate dateWithTimeIntervalSinceNow:-upTime]; + NSDate * oldSystemStartTime = _estimatedStartTime; + if (!_estimatedStartTime || ([potentialSystemStartTime compare:_estimatedStartTime] == NSOrderedAscending)) { + MTR_LOG("%@ General Diagnostics UpTime %.3lf: estimated start time %@ => %@", self, upTime, + oldSystemStartTime, potentialSystemStartTime); + _estimatedStartTime = potentialSystemStartTime; + } + + // Save estimate in the subscription resumption case, for when StartUp event uses it + _estimatedStartTimeFromGeneralDiagnosticsUpTime = potentialSystemStartTime; + } + } + } + + if (shouldReportAttribute) { + if (previousValue) { + NSMutableDictionary * mutableAttributeResponseValue = attributeResponseValue.mutableCopy; + mutableAttributeResponseValue[MTRPreviousDataKey] = previousValue; + [attributesToReport addObject:mutableAttributeResponseValue]; + } else { + [attributesToReport addObject:attributeResponseValue]; + } + [attributePathsToReport addObject:attributePath]; + } + } + + if (attributePathsToReport.count > 0) { + MTR_LOG("%@ report from reported values %@", self, attributePathsToReport); + } + + return attributesToReport; +} + +#ifdef DEBUG +- (NSUInteger)unitTestAttributeCount +{ + std::lock_guard lock(_lock); + NSUInteger count = 0; + for (MTRClusterPath * path in [self _knownClusters]) { + count += [self _clusterDataForPath:path].attributes.count; + } + return count; +} +#endif + +- (void)setPersistedClusterData:(NSDictionary *)clusterData +{ + MTR_LOG("%@ setPersistedClusterData count: %lu", self, static_cast(clusterData.count)); + if (!clusterData.count) { + return; + } + + std::lock_guard lock(_lock); + + NSAssert([self _dataStoreExists], @"Why is controller setting persisted data when we shouldn't have it?"); + + for (MTRClusterPath * clusterPath in clusterData) { + // The caller has mutable references to MTRDeviceClusterData and + // MTRClusterPath, but that should be OK, since we control all the + // callers. If that stops being OK, we'll need to copy the key and + // value here. + [_persistedClusters addObject:clusterPath]; + [_persistedClusterData setObject:clusterData[clusterPath] forKey:clusterPath]; + } + + // We have some stored data. Since we don't store data until the end of the + // initial priming report, our device cache must be primed. + _deviceCachePrimed = YES; +} + +- (void)_setLastInitialSubscribeLatency:(id)latency +{ + os_unfair_lock_assert_owner(&self->_lock); + + if (![latency isKindOfClass:NSNumber.class]) { + // Unexpected value of some sort; just ignore it. + return; + } + + _estimatedSubscriptionLatency = latency; +} + +- (void)setPersistedDeviceData:(NSDictionary *)data +{ + MTR_LOG_DEBUG("%@ setPersistedDeviceData: %@", self, data); + + std::lock_guard lock(_lock); + + // For now the only data we care about is our initial subscribe latency. + id initialSubscribeLatency = data[sLastInitialSubscribeLatencyKey]; + if (initialSubscribeLatency != nil) { + [self _setLastInitialSubscribeLatency:initialSubscribeLatency]; + } +} + +- (void)_storePersistedDeviceData +{ + os_unfair_lock_assert_owner(&self->_lock); + + auto datastore = _deviceController.controllerDataStore; + if (datastore == nil) { + // No way to store. + return; + } + + // For now the only data we have is our initial subscribe latency. + NSMutableDictionary * data = [NSMutableDictionary dictionary]; + if (_estimatedSubscriptionLatency != nil) { + data[sLastInitialSubscribeLatencyKey] = _estimatedSubscriptionLatency; + } + + [datastore storeDeviceData:[data copy] forNodeID:self.nodeID]; +} + +#ifdef DEBUG +- (MTRDeviceClusterData *)unitTestGetClusterDataForPath:(MTRClusterPath *)path +{ + std::lock_guard lock(_lock); + + return [[self _clusterDataForPath:path] copy]; +} + +- (NSSet *)unitTestGetPersistedClusters +{ + std::lock_guard lock(_lock); + + return [_persistedClusters copy]; +} + +- (BOOL)unitTestClusterHasBeenPersisted:(MTRClusterPath *)path +{ + std::lock_guard lock(_lock); + + return [_persistedClusters containsObject:path]; +} +#endif + +- (BOOL)deviceCachePrimed +{ + std::lock_guard lock(_lock); + return _deviceCachePrimed; +} + +// If value is non-nil, associate with expectedValueID +// If value is nil, remove only if expectedValueID matches +// previousValue is an out parameter +- (void)_setExpectedValue:(NSDictionary *)expectedAttributeValue + attributePath:(MTRAttributePath *)attributePath + expirationTime:(NSDate *)expirationTime + shouldReportValue:(BOOL *)shouldReportValue + attributeValueToReport:(NSDictionary **)attributeValueToReport + expectedValueID:(uint64_t)expectedValueID + previousValue:(NSDictionary **)previousValue +{ + os_unfair_lock_assert_owner(&self->_lock); + + *shouldReportValue = NO; + + NSArray * previousExpectedValue = _expectedValueCache[attributePath]; + if (previousExpectedValue) { + if (expectedAttributeValue + && ![self _attributeDataValue:expectedAttributeValue + isEqualToDataValue:previousExpectedValue[MTRDeviceExpectedValueFieldValueIndex]]) { + // Case where new expected value overrides previous expected value - report new expected value + *shouldReportValue = YES; + *attributeValueToReport = expectedAttributeValue; + *previousValue = previousExpectedValue[MTRDeviceExpectedValueFieldValueIndex]; + } else if (!expectedAttributeValue) { + // Remove previous expected value only if it's from the same setExpectedValues operation + NSNumber * previousExpectedValueID = previousExpectedValue[MTRDeviceExpectedValueFieldIDIndex]; + if (previousExpectedValueID.unsignedLongLongValue == expectedValueID) { + MTRDeviceDataValueDictionary cachedValue = [self _cachedAttributeValueForPath:attributePath]; + if (![self _attributeDataValue:previousExpectedValue[MTRDeviceExpectedValueFieldValueIndex] + isEqualToDataValue:cachedValue]) { + // Case of removing expected value that is different than read cache - report read cache value + *shouldReportValue = YES; + *attributeValueToReport = cachedValue; + *previousValue = previousExpectedValue[MTRDeviceExpectedValueFieldValueIndex]; + _expectedValueCache[attributePath] = nil; + } + } + } + } else { + MTRDeviceDataValueDictionary cachedValue = [self _cachedAttributeValueForPath:attributePath]; + if (expectedAttributeValue + && ![self _attributeDataValue:expectedAttributeValue isEqualToDataValue:cachedValue]) { + // Case where new expected value is different than read cache - report new expected value + *shouldReportValue = YES; + *attributeValueToReport = expectedAttributeValue; + *previousValue = cachedValue; + } else { + *previousValue = nil; + } + + // No need to report if new and previous expected value are both nil + } + + if (expectedAttributeValue) { + _expectedValueCache[attributePath] = @[ expirationTime, expectedAttributeValue, @(expectedValueID) ]; + } +} + +// assume lock is held +- (NSArray *)_getAttributesToReportWithNewExpectedValues:(NSArray *> *)expectedAttributeValues + expirationTime:(NSDate *)expirationTime + expectedValueID:(uint64_t *)expectedValueID +{ + os_unfair_lock_assert_owner(&self->_lock); + uint64_t expectedValueIDToReturn = _expectedValueNextID++; + + NSMutableArray * attributesToReport = [NSMutableArray array]; + NSMutableArray * attributePathsToReport = [NSMutableArray array]; + for (NSDictionary * attributeResponseValue in expectedAttributeValues) { + MTRAttributePath * attributePath = attributeResponseValue[MTRAttributePathKey]; + NSDictionary * attributeDataValue = attributeResponseValue[MTRDataKey]; + + BOOL shouldReportValue = NO; + NSDictionary * attributeValueToReport; + NSDictionary * previousValue; + [self _setExpectedValue:attributeDataValue + attributePath:attributePath + expirationTime:expirationTime + shouldReportValue:&shouldReportValue + attributeValueToReport:&attributeValueToReport + expectedValueID:expectedValueIDToReturn + previousValue:&previousValue]; + + if (shouldReportValue) { + if (previousValue) { + [attributesToReport addObject:@{ MTRAttributePathKey : attributePath, MTRDataKey : attributeValueToReport, MTRPreviousDataKey : previousValue }]; + } else { + [attributesToReport addObject:@{ MTRAttributePathKey : attributePath, MTRDataKey : attributeValueToReport }]; + } + [attributePathsToReport addObject:attributePath]; + } + } + if (expectedValueID) { + *expectedValueID = expectedValueIDToReturn; + } + + MTR_LOG("%@ report from new expected values %@", self, attributePathsToReport); + + return attributesToReport; +} + +- (void)setExpectedValues:(NSArray *> *)values expectedValueInterval:(NSNumber *)expectedValueInterval +{ + [self setExpectedValues:values expectedValueInterval:expectedValueInterval expectedValueID:nil]; +} + +// expectedValueID is an out-argument that returns an identifier to be used when removing expected values +- (void)setExpectedValues:(NSArray *> *)values + expectedValueInterval:(NSNumber *)expectedValueInterval + expectedValueID:(uint64_t *)expectedValueID +{ + // since NSTimeInterval is in seconds, convert ms into seconds in double + NSDate * expirationTime = [NSDate dateWithTimeIntervalSinceNow:expectedValueInterval.doubleValue / 1000]; + + MTR_LOG( + "%@ Setting expected values %@ with expiration time %f seconds from now", self, values, [expirationTime timeIntervalSinceNow]); + + std::lock_guard lock(_lock); + + // _getAttributesToReportWithNewExpectedValues will log attribute paths reported + NSArray * attributesToReport = [self _getAttributesToReportWithNewExpectedValues:values + expirationTime:expirationTime + expectedValueID:expectedValueID]; + [self _reportAttributes:attributesToReport]; + + [self _checkExpiredExpectedValues]; +} + +- (void)removeExpectedValuesForAttributePaths:(NSArray *)attributePaths + expectedValueID:(uint64_t)expectedValueID +{ + std::lock_guard lock(_lock); + + for (MTRAttributePath * attributePath in attributePaths) { + [self _removeExpectedValueForAttributePath:attributePath expectedValueID:expectedValueID]; + } +} + +- (void)removeExpectedValueForAttributePath:(MTRAttributePath *)attributePath expectedValueID:(uint64_t)expectedValueID +{ + std::lock_guard lock(_lock); + [self _removeExpectedValueForAttributePath:attributePath expectedValueID:expectedValueID]; +} + +- (void)_removeExpectedValueForAttributePath:(MTRAttributePath *)attributePath expectedValueID:(uint64_t)expectedValueID +{ + os_unfair_lock_assert_owner(&self->_lock); + + BOOL shouldReportValue; + NSDictionary * attributeValueToReport; + NSDictionary * previousValue; + [self _setExpectedValue:nil + attributePath:attributePath + expirationTime:nil + shouldReportValue:&shouldReportValue + attributeValueToReport:&attributeValueToReport + expectedValueID:expectedValueID + previousValue:&previousValue]; + + MTR_LOG("%@ remove expected value for path %@ should report %@", self, attributePath, shouldReportValue ? @"YES" : @"NO"); + + if (shouldReportValue) { + NSMutableDictionary * attribute = [NSMutableDictionary dictionaryWithObject:attributePath forKey:MTRAttributePathKey]; + if (attributeValueToReport) { + attribute[MTRDataKey] = attributeValueToReport; + } + if (previousValue) { + attribute[MTRPreviousDataKey] = previousValue; + } + [self _reportAttributes:@[ attribute ]]; + } +} + +- (MTRBaseDevice *)newBaseDevice +{ + return [MTRBaseDevice deviceWithNodeID:self.nodeID controller:self.deviceController]; +} + +// Client Metadata Storage + +- (NSArray *)supportedClientDataClasses +{ + return @[ [NSData class], [NSString class], [NSNumber class], [NSDictionary class], [NSArray class] ]; +} + +- (NSArray * _Nullable)clientDataKeys +{ + return [self.temporaryMetaDataCache allKeys]; +} + +- (id _Nullable)clientDataForKey:(NSString *)key +{ + if (key == nil) + return nil; + + return [self.temporaryMetaDataCache objectForKey:[NSString stringWithFormat:@"%@:-1", key]]; +} + +- (void)setClientDataForKey:(NSString *)key value:(id)value +{ + // TODO: Check supported data types, and also if they conform to NSSecureCoding, when we store these + // TODO: Need to add a delegate method, so when this value changes we call back to the client + + if (key == nil || value == nil) + return; + + if (self.temporaryMetaDataCache == nil) { + self.temporaryMetaDataCache = [NSMutableDictionary dictionary]; + } + + [self.temporaryMetaDataCache setObject:value forKey:[NSString stringWithFormat:@"%@:-1", key]]; +} + +- (void)removeClientDataForKey:(NSString *)key +{ + if (key == nil) + return; + + [self.temporaryMetaDataCache removeObjectForKey:[NSString stringWithFormat:@"%@:-1", key]]; +} + +- (NSArray * _Nullable)clientDataKeysForEndpointID:(NSNumber *)endpointID +{ + if (endpointID == nil) + return nil; + // TODO: When hooked up to storage, enumerate this better + + return [self.temporaryMetaDataCache allKeys]; +} + +- (id _Nullable)clientDataForKey:(NSString *)key endpointID:(NSNumber *)endpointID +{ + if (key == nil || endpointID == nil) + return nil; + + return [self.temporaryMetaDataCache objectForKey:[NSString stringWithFormat:@"%@:%@", key, endpointID]]; +} + +- (void)setClientDataForKey:(NSString *)key endpointID:(NSNumber *)endpointID value:(id)value +{ + if (key == nil || value == nil || endpointID == nil) + return; + + if (self.temporaryMetaDataCache == nil) { + self.temporaryMetaDataCache = [NSMutableDictionary dictionary]; + } + + [self.temporaryMetaDataCache setObject:value forKey:[NSString stringWithFormat:@"%@:%@", key, endpointID]]; +} + +- (void)removeClientDataForKey:(NSString *)key endpointID:(NSNumber *)endpointID +{ + if (key == nil || endpointID == nil) + return; + + [self.temporaryMetaDataCache removeObjectForKey:[NSString stringWithFormat:@"%@:%@", key, endpointID]]; +} + +#pragma mark Log Help + +- (nullable NSNumber *)_informationalNumberAtAttributePath:(MTRAttributePath *)attributePath +{ + auto * cachedData = [self _cachedAttributeValueForPath:attributePath]; + + auto * attrReport = [[MTRAttributeReport alloc] initWithResponseValue:@{ + MTRAttributePathKey : attributePath, + MTRDataKey : cachedData, + } + error:nil]; + + return attrReport.value; +} + +- (nullable NSNumber *)_informationalVendorID +{ + auto * vendorIDPath = [MTRAttributePath attributePathWithEndpointID:@(kRootEndpointId) + clusterID:@(MTRClusterIDTypeBasicInformationID) + attributeID:@(MTRClusterBasicAttributeVendorIDID)]; + + return [self _informationalNumberAtAttributePath:vendorIDPath]; +} + +- (nullable NSNumber *)_informationalProductID +{ + auto * productIDPath = [MTRAttributePath attributePathWithEndpointID:@(kRootEndpointId) + clusterID:@(MTRClusterIDTypeBasicInformationID) + attributeID:@(MTRClusterBasicAttributeProductIDID)]; + + return [self _informationalNumberAtAttributePath:productIDPath]; +} + +- (void)_addInformationalAttributesToCurrentMetricScope +{ + using namespace chip::Tracing::DarwinFramework; + MATTER_LOG_METRIC(kMetricDeviceVendorID, [self _informationalVendorID].unsignedShortValue); + MATTER_LOG_METRIC(kMetricDeviceProductID, [self _informationalProductID].unsignedShortValue); + BOOL usesThread = [self _deviceUsesThread]; + MATTER_LOG_METRIC(kMetricDeviceUsesThread, usesThread); +} + +@end + +/* BEGIN DRAGONS: Note methods here cannot be renamed, and are used by private callers, do not rename, remove or modify behavior here */ + +@implementation MTRDevice_Concrete (MatterPrivateForInternalDragonsDoNotFeed) + +- (BOOL)_deviceHasActiveSubscription +{ + std::lock_guard lock(_lock); + + // TODO: This should always return YES for thread devices + return HaveSubscriptionEstablishedRightNow(_internalDeviceState); +} + +- (void)_deviceMayBeReachable +{ + MTR_LOG("%@ _deviceMayBeReachable called", self); + // TODO: This should only be allowed for thread devices + [_deviceController asyncDispatchToMatterQueue:^{ + [self _triggerResubscribeWithReason:@"SPI client indicated the device may now be reachable" + nodeLikelyReachable:YES]; + } errorHandler:nil]; +} + +/* END DRAGONS */ + +@end + +@implementation MTRDevice_Concrete (Deprecated) + ++ (MTRDevice *)deviceWithNodeID:(uint64_t)nodeID deviceController:(MTRDeviceController *)deviceController +{ + return [self deviceWithNodeID:@(nodeID) controller:deviceController]; +} + +- (void)invokeCommandWithEndpointID:(NSNumber *)endpointID + clusterID:(NSNumber *)clusterID + commandID:(NSNumber *)commandID + commandFields:(id)commandFields + expectedValues:(NSArray *> * _Nullable)expectedValues + expectedValueInterval:(NSNumber * _Nullable)expectedValueInterval + timedInvokeTimeout:(NSNumber * _Nullable)timeout + clientQueue:(dispatch_queue_t)queue + completion:(MTRDeviceResponseHandler)completion +{ + [self invokeCommandWithEndpointID:endpointID + clusterID:clusterID + commandID:commandID + commandFields:commandFields + expectedValues:expectedValues + expectedValueInterval:expectedValueInterval + timedInvokeTimeout:timeout + queue:queue + completion:completion]; +} + +@end + +#pragma mark - SubscriptionCallback +namespace { +void SubscriptionCallback::OnEventData(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus) +{ + if (mEventReports == nil) { + // Never got a OnReportBegin? Not much to do other than tear things down. + ReportError(CHIP_ERROR_INCORRECT_STATE); + return; + } + + MTREventPath * eventPath = [[MTREventPath alloc] initWithPath:aEventHeader.mPath]; + if (apStatus != nullptr) { + [mEventReports addObject:@ { MTREventPathKey : eventPath, MTRErrorKey : [MTRError errorForIMStatus:*apStatus] }]; + } else if (apData == nullptr) { + [mEventReports addObject:@ { + MTREventPathKey : eventPath, + MTRErrorKey : [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_ARGUMENT] + }]; + } else { + id value = MTRDecodeDataValueDictionaryFromCHIPTLV(apData); + if (value == nil) { + MTR_LOG_ERROR("Failed to decode event data for path %@", eventPath); + [mEventReports addObject:@ { + MTREventPathKey : eventPath, + MTRErrorKey : [MTRError errorForCHIPErrorCode:CHIP_ERROR_DECODE_FAILED], + }]; + } else { + [mEventReports addObject:[MTRBaseDevice eventReportForHeader:aEventHeader andData:value]]; + } + } + + QueueInterimReport(); +} + +void SubscriptionCallback::OnAttributeData( + const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus) +{ + if (aPath.IsListItemOperation()) { + ReportError(CHIP_ERROR_INCORRECT_STATE); + return; + } + + if (mAttributeReports == nil) { + // Never got a OnReportBegin? Not much to do other than tear things down. + ReportError(CHIP_ERROR_INCORRECT_STATE); + return; + } + + MTRAttributePath * attributePath = [[MTRAttributePath alloc] initWithPath:aPath]; + if (aStatus.mStatus != Status::Success) { + [mAttributeReports addObject:@ { MTRAttributePathKey : attributePath, MTRErrorKey : [MTRError errorForIMStatus:aStatus] }]; + } else if (apData == nullptr) { + [mAttributeReports addObject:@ { + MTRAttributePathKey : attributePath, + MTRErrorKey : [MTRError errorForCHIPErrorCode:CHIP_ERROR_INVALID_ARGUMENT] + }]; + } else { + NSNumber * dataVersionNumber = aPath.mDataVersion.HasValue() ? @(aPath.mDataVersion.Value()) : nil; + NSDictionary * value = MTRDecodeDataValueDictionaryFromCHIPTLV(apData, dataVersionNumber); + if (value == nil) { + MTR_LOG_ERROR("Failed to decode attribute data for path %@", attributePath); + [mAttributeReports addObject:@ { + MTRAttributePathKey : attributePath, + MTRErrorKey : [MTRError errorForCHIPErrorCode:CHIP_ERROR_DECODE_FAILED], + }]; + } else { + [mAttributeReports addObject:@ { MTRAttributePathKey : attributePath, MTRDataKey : value }]; + } + } + + QueueInterimReport(); +} + +uint32_t SubscriptionCallback::ComputeTimeTillNextSubscription() +{ + uint32_t maxWaitTimeInMsec = 0; + uint32_t waitTimeInMsec = 0; + uint32_t minWaitTimeInMsec = 0; + + if (mResubscriptionNumRetries <= CHIP_RESUBSCRIBE_MAX_FIBONACCI_STEP_INDEX) { + maxWaitTimeInMsec = GetFibonacciForIndex(mResubscriptionNumRetries) * CHIP_RESUBSCRIBE_WAIT_TIME_MULTIPLIER_MS; + } else { + maxWaitTimeInMsec = CHIP_RESUBSCRIBE_MAX_RETRY_WAIT_INTERVAL_MS; + } + + if (maxWaitTimeInMsec != 0) { + minWaitTimeInMsec = (CHIP_RESUBSCRIBE_MIN_WAIT_TIME_INTERVAL_PERCENT_PER_STEP * maxWaitTimeInMsec) / 100; + waitTimeInMsec = minWaitTimeInMsec + (Crypto::GetRandU32() % (maxWaitTimeInMsec - minWaitTimeInMsec)); + } + + return waitTimeInMsec; +} + +CHIP_ERROR SubscriptionCallback::OnResubscriptionNeeded(ReadClient * apReadClient, CHIP_ERROR aTerminationCause) +{ + // No need to check ReadClient internal state is Idle because ReadClient only calls OnResubscriptionNeeded after calling ClearActiveSubscriptionState(), which sets the state to Idle. + + // This part is copied from ReadClient's DefaultResubscribePolicy: + auto timeTillNextResubscriptionMs = ComputeTimeTillNextSubscription(); + ChipLogProgress(DataManagement, + "Will try to resubscribe to %02x:" ChipLogFormatX64 " at retry index %" PRIu32 " after %" PRIu32 + "ms due to error %" CHIP_ERROR_FORMAT, + apReadClient->GetFabricIndex(), ChipLogValueX64(apReadClient->GetPeerNodeId()), mResubscriptionNumRetries, timeTillNextResubscriptionMs, + aTerminationCause.Format()); + + // Schedule a maximum time resubscription, to be triggered with TriggerResubscribeIfScheduled after a separate timer. + // This way the aReestablishCASE value is saved, and the sanity checks in ScheduleResubscription are observed and returned. + ReturnErrorOnFailure(apReadClient->ScheduleResubscription(UINT32_MAX, NullOptional, aTerminationCause == CHIP_ERROR_TIMEOUT)); + + // Not as good a place to increment as when resubscription timer fires, but as is, this should be as good, because OnResubscriptionNeeded is only called from ReadClient's Close() while Idle, and nothing should cause this to happen + mResubscriptionNumRetries++; + + auto error = [MTRError errorForCHIPErrorCode:aTerminationCause]; + CallResubscriptionScheduledHandler(error, @(timeTillNextResubscriptionMs)); + + return CHIP_NO_ERROR; +} +} // anonymous namespace diff --git a/src/darwin/Framework/CHIP/MTRDevice_Internal.h b/src/darwin/Framework/CHIP/MTRDevice_Internal.h index 1416aa29dfac29..943e939f47f204 100644 --- a/src/darwin/Framework/CHIP/MTRDevice_Internal.h +++ b/src/darwin/Framework/CHIP/MTRDevice_Internal.h @@ -66,6 +66,7 @@ MTR_TESTABLE @end @interface MTRDevice () +- (instancetype)initForSubclasses; - (instancetype)initWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller; // Called from MTRClusters for writes and commands @@ -122,16 +123,16 @@ MTR_TESTABLE @end -#pragma mark - Utility for clamping numbers -// Returns a NSNumber object that is aNumber if it falls within the range [min, max]. -// Returns min or max, if it is below or above, respectively. -NSNumber * MTRClampedNumber(NSNumber * aNumber, NSNumber * min, NSNumber * max); - #pragma mark - Constants static NSString * const kDefaultSubscriptionPoolSizeOverrideKey = @"subscriptionPoolSizeOverride"; static NSString * const kTestStorageUserDefaultEnabledKey = @"enableTestStorage"; +// ex-MTRDeviceClusterData constants +static NSString * const sDataVersionKey = @"dataVersion"; +static NSString * const sAttributesKey = @"attributes"; +static NSString * const sLastInitialSubscribeLatencyKey = @"lastInitialSubscribeLatency"; + // Declared inside platform, but noting here for reference // static NSString * const kSRPTimeoutInMsecsUserDefaultKey = @"SRPTimeoutInMSecsOverride"; diff --git a/src/darwin/Framework/CHIP/MTRUtilities.h b/src/darwin/Framework/CHIP/MTRUtilities.h index 754f5da7ecadd6..a5d780383a1ae9 100644 --- a/src/darwin/Framework/CHIP/MTRUtilities.h +++ b/src/darwin/Framework/CHIP/MTRUtilities.h @@ -24,4 +24,6 @@ NS_ASSUME_NONNULL_BEGIN */ MTR_EXTERN BOOL MTREqualObjects(id _Nullable a, id _Nullable b); +MTR_EXTERN NSNumber * MTRClampedNumber(NSNumber * aNumber, NSNumber * min, NSNumber * max); + NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRUtilities.mm b/src/darwin/Framework/CHIP/MTRUtilities.mm index e9698ab24d0b41..0b46ff93250f59 100644 --- a/src/darwin/Framework/CHIP/MTRUtilities.mm +++ b/src/darwin/Framework/CHIP/MTRUtilities.mm @@ -32,3 +32,13 @@ BOOL MTREqualObjects(id _Nullable a, id _Nullable b) // Otherwise work on equality, given that we're both non nil return [a isEqual:b]; } + +NSNumber * MTRClampedNumber(NSNumber * aNumber, NSNumber * min, NSNumber * max) +{ + if ([aNumber compare:min] == NSOrderedAscending) { + return min; + } else if ([aNumber compare:max] == NSOrderedDescending) { + return max; + } + return aNumber; +} diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj index 055a6c9efbcc3e..10884a64f4ffe4 100644 --- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj +++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj @@ -302,6 +302,8 @@ 99AECC802798A57F00B6355B /* MTRCommissioningParameters.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99AECC7F2798A57E00B6355B /* MTRCommissioningParameters.mm */; }; 99C65E10267282F1003402F6 /* MTRControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 99C65E0F267282F1003402F6 /* MTRControllerTests.m */; }; 99D466E12798936D0089A18F /* MTRCommissioningParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 99D466E02798936D0089A18F /* MTRCommissioningParameters.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9BDA2A062C5D9AF800A32BDD /* MTRDevice_Concrete.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BDA2A052C5D9AF800A32BDD /* MTRDevice_Concrete.mm */; }; + 9BDA2A082C5D9AFB00A32BDD /* MTRDevice_Concrete.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BDA2A072C5D9AFB00A32BDD /* MTRDevice_Concrete.h */; }; AF1CB86E2874B03B00865A96 /* MTROTAProviderDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = AF1CB86D2874B03B00865A96 /* MTROTAProviderDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; AF1CB8702874B04C00865A96 /* MTROTAProviderDelegateBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = AF1CB86F2874B04C00865A96 /* MTROTAProviderDelegateBridge.h */; }; AF5F90FF2878D351005503FA /* MTROTAProviderDelegateBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = AF5F90FE2878D351005503FA /* MTROTAProviderDelegateBridge.mm */; }; @@ -729,6 +731,8 @@ 99AECC7F2798A57E00B6355B /* MTRCommissioningParameters.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRCommissioningParameters.mm; sourceTree = ""; }; 99C65E0F267282F1003402F6 /* MTRControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRControllerTests.m; sourceTree = ""; }; 99D466E02798936D0089A18F /* MTRCommissioningParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRCommissioningParameters.h; sourceTree = ""; }; + 9BDA2A052C5D9AF800A32BDD /* MTRDevice_Concrete.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDevice_Concrete.mm; sourceTree = ""; }; + 9BDA2A072C5D9AFB00A32BDD /* MTRDevice_Concrete.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRDevice_Concrete.h; sourceTree = ""; }; AF1CB86D2874B03B00865A96 /* MTROTAProviderDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTROTAProviderDelegate.h; sourceTree = ""; }; AF1CB86F2874B04C00865A96 /* MTROTAProviderDelegateBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTROTAProviderDelegateBridge.h; sourceTree = ""; }; AF5F90FE2878D351005503FA /* MTROTAProviderDelegateBridge.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTROTAProviderDelegateBridge.mm; sourceTree = ""; }; @@ -1301,6 +1305,8 @@ 7596A84A287636C1004DAE0E /* MTRDevice_Internal.h */, 7596A84228762729004DAE0E /* MTRDevice.h */, 7596A84328762729004DAE0E /* MTRDevice.mm */, + 9BDA2A072C5D9AFB00A32BDD /* MTRDevice_Concrete.h */, + 9BDA2A052C5D9AF800A32BDD /* MTRDevice_Concrete.mm */, 88EBF8CB27FABDD500686BC1 /* MTRDeviceAttestationDelegate.h */, 7534F12728BFF20300390851 /* MTRDeviceAttestationDelegate_Internal.h */, 7534F12628BFF20300390851 /* MTRDeviceAttestationDelegate.mm */, @@ -1600,6 +1606,7 @@ 5117DD3929A931AE00FFA1AA /* MTROperationalBrowser.h in Headers */, 2C1B027B2641DB4E00780EF1 /* MTROperationalCredentialsDelegate.h in Headers */, 5173A47529C0E2ED00F67F48 /* MTRFabricInfo_Internal.h in Headers */, + 9BDA2A082C5D9AFB00A32BDD /* MTRDevice_Concrete.h in Headers */, 3D843717294979230070D20A /* MTRClusters_Internal.h in Headers */, 7596A85728788557004DAE0E /* MTRClusters.h in Headers */, 99D466E12798936D0089A18F /* MTRCommissioningParameters.h in Headers */, @@ -2001,6 +2008,7 @@ 7596A85528788557004DAE0E /* MTRClusters.mm in Sources */, 88EBF8CF27FABDD500686BC1 /* MTRDeviceAttestationDelegateBridge.mm in Sources */, 5A6FEC9827B5C6AF00F25F42 /* MTRDeviceOverXPC.mm in Sources */, + 9BDA2A062C5D9AF800A32BDD /* MTRDevice_Concrete.mm in Sources */, 514654492A72F9DF00904E61 /* MTRDemuxingStorage.mm in Sources */, 1E4D655229C30A8700BC3478 /* MTRCommissionableBrowser.mm in Sources */, 88FA798E2B7B257100CD4B6F /* MTRMetricsCollector.mm in Sources */, From d7ad0956bfc5465bbf201c183e6d66a9a9e4b5ca Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Wed, 7 Aug 2024 07:11:53 +0200 Subject: [PATCH 29/41] [Tizen] Strip unit test executables to save CI storage (#34810) * Add support stripping all symbols from executables * Compile Tizen with -fPIC and -pie * Re-enable Tizen QEMU workflow --- .github/workflows/qemu.yaml | 9 ++------- build/config/compiler/BUILD.gn | 6 +++++- build/config/compiler/compiler.gni | 9 ++++++--- scripts/build/builders/tizen.py | 4 ++++ third_party/tizen/tizen_sdk.gni | 2 +- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/.github/workflows/qemu.yaml b/.github/workflows/qemu.yaml index be2320f975beae..051af08a2893da 100644 --- a/.github/workflows/qemu.yaml +++ b/.github/workflows/qemu.yaml @@ -27,7 +27,7 @@ concurrency: env: CHIP_NO_LOG_TIMESTAMPS: true - + jobs: qemu-esp32: @@ -75,12 +75,7 @@ jobs: name: Tizen runs-on: ubuntu-latest - # NOTE: job temporarely disabled as it seems flaky. The flake does not result in usable - # logs so the current theory is that we run out of space. This is unusual as - # larger docker images succeed at bootstrap, however it needs more investigation - # to detect an exact/real root cause. - if: false - # if: github.actor != 'restyled-io[bot]' + if: github.actor != 'restyled-io[bot]' container: image: ghcr.io/project-chip/chip-build-tizen-qemu:54 diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 3de1749b37d58a..fee0d745f6d136 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn @@ -334,7 +334,11 @@ config("warnings_third_party") { } config("symbols_default") { - cflags = [ "-g${symbol_level}" ] + if (strip_symbols) { + cflags = [ "-s" ] + } else { + cflags = [ "-g${symbol_level}" ] + } } config("std_default") { diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni index 74dc224f3ecec7..63b1840bc884d2 100644 --- a/build/config/compiler/compiler.gni +++ b/build/config/compiler/compiler.gni @@ -30,11 +30,11 @@ declare_args() { symbol_level = 2 # Enable position independent code (-fPIC). - enable_pic = - current_os == "linux" || current_os == "mac" || current_os == "android" + enable_pic = current_os == "linux" || current_os == "mac" || + current_os == "android" || current_os == "tizen" # Enable position independent executables (-pie). - enable_pie = current_os == "linux" + enable_pie = current_os == "linux" || current_os == "tizen" # Remove unwind tables from the binary to save space. exclude_unwind_tables = current_os != "android" @@ -48,6 +48,9 @@ declare_args() { # enable libfuzzer is_libfuzzer = false + # Remove all symbol table and relocation information from the binary. + strip_symbols = false + # Generate code coverage analysis artifacts when enabled. use_coverage = false diff --git a/scripts/build/builders/tizen.py b/scripts/build/builders/tizen.py index 97124328c5dd1e..b9b9c59661cf74 100644 --- a/scripts/build/builders/tizen.py +++ b/scripts/build/builders/tizen.py @@ -117,6 +117,10 @@ def __init__(self, if app == TizenApp.TESTS: self.extra_gn_options.append('chip_build_tests=true') + # Tizen test driver creates ISO image with all unit test files. So, + # it uses twice as much space as regular build. Due to CI storage + # limitations, we need to strip debug symbols from executables. + self.extra_gn_options.append('strip_symbols=true') self.build_command = 'check' if not enable_ble: diff --git a/third_party/tizen/tizen_sdk.gni b/third_party/tizen/tizen_sdk.gni index ebbc8dadd077d0..7f711c693ea599 100644 --- a/third_party/tizen/tizen_sdk.gni +++ b/third_party/tizen/tizen_sdk.gni @@ -189,7 +189,7 @@ template("tizen_qemu_mkisofs") { "mkisofs", "-input-charset=default", "-VCHIP", # Volume ID = CHIP - "-JRU", # Joliet + Rock Ridge with untranslated filenames + "-JrU", # Joliet + Rock Ridge with untranslated filenames ] # Exclude files from the ISO image which might otherwise be included From 587665db819a1c95c231f9464699249d15173aba Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Wed, 7 Aug 2024 17:20:24 +1200 Subject: [PATCH 30/41] Fix network-manager app device type id (#34831) --- .../network-manager-app/linux/include/CHIPProjectAppConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/network-manager-app/linux/include/CHIPProjectAppConfig.h b/examples/network-manager-app/linux/include/CHIPProjectAppConfig.h index 6fa4c82568eb70..1ef9862a272938 100644 --- a/examples/network-manager-app/linux/include/CHIPProjectAppConfig.h +++ b/examples/network-manager-app/linux/include/CHIPProjectAppConfig.h @@ -18,7 +18,7 @@ #pragma once -#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 0xFFF10010 // TODO: ID-TBD +#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 144 // 0x0090 Network Infrastructure Manager #define CHIP_DEVICE_CONFIG_DEVICE_NAME "Network Infrastructure Manager" // Inherit defaults from config/standalone/CHIPProjectConfig.h From cea7fd8020286e96fbcef37da237a58094bb22d5 Mon Sep 17 00:00:00 2001 From: Junior Martinez <67972863+jmartinez-silabs@users.noreply.github.com> Date: Wed, 7 Aug 2024 10:02:44 -0400 Subject: [PATCH 31/41] Fixes for the color control quiet reporting (#34820) * MarkAttributeDirty::kYes instead of kIfChanged for QuietReporting to insure the value is reported. Fix Start Or End of transition Quiet report to only report if the attribute value changed since the last quiet report * apply same tweak for start/end of transition to the lvl control. * re-enable the disabled tc_cc_2_2 steps * Restyled by autopep8 * address comments --------- Co-authored-by: Restyled.io --- .../color-control-server/color-control-server.cpp | 12 ++++++------ src/app/clusters/level-control/level-control.cpp | 2 +- src/python_testing/TC_CC_2_2.py | 12 +++++------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/app/clusters/color-control-server/color-control-server.cpp b/src/app/clusters/color-control-server/color-control-server.cpp index c4de9f9d9461ef..4a4fc69b4efe07 100644 --- a/src/app/clusters/color-control-server/color-control-server.cpp +++ b/src/app/clusters/color-control-server/color-control-server.cpp @@ -3113,15 +3113,15 @@ void ColorControlServer::levelControlColorTempChangeCommand(EndpointId endpoint) * - When it changes from null to any other value and vice versa. (Implicit to the QuieterReportingAttribute class) * * The QuietReportAttribute class is updated with the new value and when the report conditions are met, - * this function will return MarkAttributeDirty::kIfChanged. + * this function will return MarkAttributeDirty::kYes. * It is expected that the user will use this return value to trigger a reporting mechanism for the attribute with the new value * (Which was updated in the quietReporter) * * @param quietReporter: The QuieterReportingAttribute object for the attribute to update. * @param newValue: Value to update the attribute with * @param isStartOrEndOfTransition: Boolean that indicatse whether the update is occurring at the start or end of a level transition - * @return MarkAttributeDirty::kIfChanged when the attribute must be maredk dirty and be reported. MarkAttributeDirty::kNo when it - * when it no report is needed. + * @return MarkAttributeDirty::kYes when the attribute must be marked dirty and be reported. MarkAttributeDirty::kNo when + * no report is needed. */ template MarkAttributeDirty ColorControlServer::SetQuietReportAttribute(QuieterReportingAttribute & quietReporter, V newValue, @@ -3132,7 +3132,7 @@ MarkAttributeDirty ColorControlServer::SetQuietReportAttribute(QuieterReportingA if (isStartOrEndOfTransition) { - // At the start or end of the movement/transition we must report + // At the start or end of the movement/transition we must report if the value changed auto predicate = [](const typename QuieterReportingAttribute::SufficientChangePredicateCandidate &) -> bool { return true; }; @@ -3155,7 +3155,7 @@ MarkAttributeDirty ColorControlServer::SetQuietReportAttribute(QuieterReportingA dirtyState = quietReporter.SetValue(newValue, now, predicate); } - return (dirtyState == AttributeDirtyState::kMustReport) ? MarkAttributeDirty::kIfChanged : MarkAttributeDirty::kNo; + return (dirtyState == AttributeDirtyState::kMustReport) ? MarkAttributeDirty::kYes : MarkAttributeDirty::kNo; } /* @@ -3180,7 +3180,7 @@ Status ColorControlServer::SetQuietReportRemainingTime(EndpointId endpoint, uint // - kMarkDirtyOnIncrement : When the value increases. if (quietRemainingTime[epIndex].SetValue(newRemainingTime, now) == AttributeDirtyState::kMustReport) { - markDirty = MarkAttributeDirty::kIfChanged; + markDirty = MarkAttributeDirty::kYes; } return Attributes::RemainingTime::Set(endpoint, quietRemainingTime[epIndex].value().Value(), markDirty); diff --git a/src/app/clusters/level-control/level-control.cpp b/src/app/clusters/level-control/level-control.cpp index 00d8a2e496518f..231a542c2ef1b4 100644 --- a/src/app/clusters/level-control/level-control.cpp +++ b/src/app/clusters/level-control/level-control.cpp @@ -545,7 +545,7 @@ static void writeRemainingTime(EndpointId endpoint, uint16_t remainingTimeMs) markDirty = MarkAttributeDirty::kYes; } - Attributes::RemainingTime::Set(endpoint, state->quietRemainingTime.value().ValueOr(0), markDirty); + Attributes::RemainingTime::Set(endpoint, state->quietRemainingTime.value().Value(), markDirty); } #endif // IGNORE_LEVEL_CONTROL_CLUSTER_LEVEL_CONTROL_REMAINING_TIME } diff --git a/src/python_testing/TC_CC_2_2.py b/src/python_testing/TC_CC_2_2.py index 66ed2a8f563777..4f6a21b1ba2771 100644 --- a/src/python_testing/TC_CC_2_2.py +++ b/src/python_testing/TC_CC_2_2.py @@ -160,8 +160,7 @@ def accumulate_reports(): def check_report_counts(attr: ClusterObjects.ClusterAttributeDescriptor): count = sub_handler.attribute_report_counts[attr] - # TODO: should be 12 - see issue #34646 - # asserts.assert_less_equal(count, 12, "More than 12 reports received") + asserts.assert_less_equal(count, 12, "More than 12 reports received") asserts.assert_less_equal(count, gather_time, f"More than {gather_time} reports received") self.step(9) @@ -270,17 +269,16 @@ def check_report_counts(attr: ClusterObjects.ClusterAttributeDescriptor): time.sleep(20) self.step(34) - # TODO: Re-enable checks 34, 36 when #34643 is addressed logging.info(f'received reports: {sub_handler.attribute_reports[cc.Attributes.RemainingTime]}') - # count = sub_handler.attribute_report_counts[cc.Attributes.RemainingTime] - # asserts.assert_equal(count, 3, "Unexpected number of reports received") + count = sub_handler.attribute_report_counts[cc.Attributes.RemainingTime] + asserts.assert_equal(count, 3, "Unexpected number of reports received") self.step(35) asserts.assert_equal(sub_handler.attribute_reports[cc.Attributes.RemainingTime][0].value, 100, "Unexpected first report") self.step(36) - # asserts.assert_almost_equal( - # sub_handler.attribute_reports[cc.Attributes.RemainingTime][1].value, 0, delta=10, msg="Unexpected second report") + asserts.assert_almost_equal( + sub_handler.attribute_reports[cc.Attributes.RemainingTime][1].value, 150, delta=10, msg="Unexpected second report") self.step(37) asserts.assert_equal(sub_handler.attribute_reports[cc.Attributes.RemainingTime][-1].value, 0, "Unexpected last report") From 8bdc3c260100dcaf3aad068caf9fd237fd459a1e Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Wed, 7 Aug 2024 10:26:33 -0400 Subject: [PATCH 32/41] Remove code duplication for CHIP_ERROR to ClusterCode conversion. (#34752) * Remove code duplication for CHIP_ERROR to ClusterCode conversion. We have a complete implementation of this in ClusterStatusCode. Remove the logic in StatusIB and use the ClusterStatusCode one instead. Generally StatusIB is just a ClusterStatusCode ontainer, however due to direct TLV reads, it splits out its contents. I only updated the constructor to use common code. * Move the chip-error conversion from statusIB into the header and made it re-use code --------- Co-authored-by: Andrei Litvin --- src/app/MessageDef/StatusIB.cpp | 26 +------------------------- src/app/MessageDef/StatusIB.h | 2 +- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/src/app/MessageDef/StatusIB.cpp b/src/app/MessageDef/StatusIB.cpp index d612f549aeeae1..63012cc64f7f1f 100644 --- a/src/app/MessageDef/StatusIB.cpp +++ b/src/app/MessageDef/StatusIB.cpp @@ -24,6 +24,7 @@ #include "StatusIB.h" #include "MessageDefHelper.h" +#include "protocols/interaction_model/StatusCode.h" #include #include @@ -149,31 +150,6 @@ CHIP_ERROR StatusIB::ToChipError() const return ChipError(ChipError::SdkPart::kIMGlobalStatus, to_underlying(mStatus)); } -StatusIB::StatusIB(CHIP_ERROR aError) -{ - if (aError.IsPart(ChipError::SdkPart::kIMClusterStatus)) - { - mStatus = Status::Failure; - mClusterStatus = MakeOptional(aError.GetSdkCode()); - return; - } - - mClusterStatus = NullOptional; - if (aError == CHIP_NO_ERROR) - { - mStatus = Status::Success; - return; - } - - if (aError.IsPart(ChipError::SdkPart::kIMGlobalStatus)) - { - mStatus = static_cast(aError.GetSdkCode()); - return; - } - - mStatus = Status::Failure; -} - namespace { bool FormatStatusIBError(char * buf, uint16_t bufSize, CHIP_ERROR err) { diff --git a/src/app/MessageDef/StatusIB.h b/src/app/MessageDef/StatusIB.h index 291a68c7fd295d..a0087f4849201d 100644 --- a/src/app/MessageDef/StatusIB.h +++ b/src/app/MessageDef/StatusIB.h @@ -60,7 +60,7 @@ struct StatusIB } } - explicit StatusIB(CHIP_ERROR error); + explicit StatusIB(CHIP_ERROR error) : StatusIB(Protocols::InteractionModel::ClusterStatusCode(error)) {} enum class Tag : uint8_t { From 3a5e3db0d47671b467a26011c98e3c2da2b500be Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Wed, 7 Aug 2024 10:26:45 -0400 Subject: [PATCH 33/41] Use explicit storage for ActionReturnStatus::c_str (#34746) * Use explicit storage for ActionReturnStatus::c_str Allocating some global storage for this is both not thread-safe and wastes RAM. Use the stack for the tiny amount of storage (relatively ... same as 4 integers) that a return status string needs. * Add unit tests and fix concatenation bug * Restyle * Undo header addition that seems wrong * Update comment to justify chosen storage size * Restyle * Fix unit test --------- Co-authored-by: Andrei Litvin --- .../ActionReturnStatus.cpp | 25 +++++------ .../data-model-provider/ActionReturnStatus.h | 23 +++++++--- .../StringBuilderAdapters.cpp | 3 +- .../tests/TestActionReturnStatus.cpp | 42 +++++++++++++++++++ src/app/reporting/Read-Checked.cpp | 7 ++-- src/app/reporting/Read-DataModel.cpp | 3 +- 6 files changed, 78 insertions(+), 25 deletions(-) diff --git a/src/app/data-model-provider/ActionReturnStatus.cpp b/src/app/data-model-provider/ActionReturnStatus.cpp index 7857246a0e861f..cbf501072c1f69 100644 --- a/src/app/data-model-provider/ActionReturnStatus.cpp +++ b/src/app/data-model-provider/ActionReturnStatus.cpp @@ -149,45 +149,42 @@ bool ActionReturnStatus::IsOutOfSpaceEncodingResponse() const return false; } -const char * ActionReturnStatus::c_str() const +const char * ActionReturnStatus::c_str(ActionReturnStatus::StringStorage & storage) const { - - // Generally size should be sufficient. - // len("Status<123>, Code 255") == 21 (and then 22 for null terminator. We have slack.) - static chip::StringBuilder<32> sFormatBuffer; - if (const CHIP_ERROR * err = std::get_if(&mReturnStatus)) { #if CHIP_CONFIG_ERROR_FORMAT_AS_STRING return err->Format(); // any length #else - sFormatBuffer.Reset().AddFormat("%" CHIP_ERROR_FORMAT, err->Format()); - return sFormatBuffer.c_str(); + storage.formatBuffer.Reset().AddFormat("%" CHIP_ERROR_FORMAT, err->Format()); + return storage.formatBuffer.c_str(); #endif } if (const ClusterStatusCode * status = std::get_if(&mReturnStatus)) { + storage.formatBuffer.Reset(); + #if CHIP_CONFIG_IM_STATUS_CODE_VERBOSE_FORMAT - sFormatBuffer.AddFormat("%s(%d)", Protocols::InteractionModel::StatusName(status->GetStatus()), - static_cast(status->GetStatus())); + storage.formatBuffer.AddFormat("%s(%d)", Protocols::InteractionModel::StatusName(status->GetStatus()), + static_cast(status->GetStatus())); #else if (status->IsSuccess()) { - sFormatBuffer.Add("Success"); + storage.formatBuffer.Add("Success"); } else { - sFormatBuffer.AddFormat("Status<%d>", static_cast(status->GetStatus())); + storage.formatBuffer.AddFormat("Status<%d>", static_cast(status->GetStatus())); } #endif chip::Optional clusterCode = status->GetClusterSpecificCode(); if (clusterCode.HasValue()) { - sFormatBuffer.AddFormat(", Code %d", static_cast(clusterCode.Value())); + storage.formatBuffer.AddFormat(", Code %d", static_cast(clusterCode.Value())); } - return sFormatBuffer.c_str(); + return storage.formatBuffer.c_str(); } // all std::variant cases exhausted diff --git a/src/app/data-model-provider/ActionReturnStatus.h b/src/app/data-model-provider/ActionReturnStatus.h index 516541483ad068..f24d0bf2099e42 100644 --- a/src/app/data-model-provider/ActionReturnStatus.h +++ b/src/app/data-model-provider/ActionReturnStatus.h @@ -44,6 +44,21 @@ namespace DataModel { class ActionReturnStatus { public: + /// Provides storage for the c_str() call for the action status. + struct StringStorage + { + // Generally size should be sufficient. + // The longest status code from StatusCodeList is NO_UPSTREAM_SUBSCRIPTION(197) + // so we need space for one of: + // "NO_UPSTREAM_SUBSCRIPTION(197)\0" = 30 // explicit verbose status code + // "FAILURE(1), Code 255\0") // cluster failure, verbose + // "SUCCESS(0), Code 255\0") // cluster success, verbose + // "Status<197>, Code 255\0") // Cluster failure, non-verbose + // + // CHIP_ERROR has its own (global/static!) storage + chip::StringBuilder<32> formatBuffer; + }; + ActionReturnStatus(CHIP_ERROR error) : mReturnStatus(error) {} ActionReturnStatus(Protocols::InteractionModel::Status status) : mReturnStatus(Protocols::InteractionModel::ClusterStatusCode(status)) @@ -81,12 +96,8 @@ class ActionReturnStatus /// Get the formatted string of this status. /// - /// NOTE: this is NOT thread safe in the general case, however the safety guarantees - /// are similar to chip::ErrorStr which also assumes a static buffer. - /// - /// Use this in the chip main event loop (and since that is a single thread, - /// there should be no races) - const char * c_str() const; + /// May use `storage` for storying the actual underlying character string. + const char * c_str(StringStorage & storage) const; private: std::variant mReturnStatus; diff --git a/src/app/data-model-provider/StringBuilderAdapters.cpp b/src/app/data-model-provider/StringBuilderAdapters.cpp index 93ad9863fc9762..5b8f6db5eab31c 100644 --- a/src/app/data-model-provider/StringBuilderAdapters.cpp +++ b/src/app/data-model-provider/StringBuilderAdapters.cpp @@ -23,7 +23,8 @@ template <> StatusWithSize ToString(const chip::app::DataModel::ActionReturnStatus & status, pw::span buffer) { - return pw::string::Format(buffer, "ActionReturnStatus<%s>", status.c_str()); + chip::app::DataModel::ActionReturnStatus::StringStorage storage; + return pw::string::Format(buffer, "ActionReturnStatus<%s>", status.c_str(storage)); } } // namespace pw diff --git a/src/app/data-model-provider/tests/TestActionReturnStatus.cpp b/src/app/data-model-provider/tests/TestActionReturnStatus.cpp index a194c0838d7d12..8ca1993d149e1a 100644 --- a/src/app/data-model-provider/tests/TestActionReturnStatus.cpp +++ b/src/app/data-model-provider/tests/TestActionReturnStatus.cpp @@ -111,3 +111,45 @@ TEST(TestActionReturnStatus, TestStatusCode) ASSERT_EQ(ActionReturnStatus(CHIP_IM_CLUSTER_STATUS(0x12)).GetStatusCode(), ClusterStatusCode::ClusterSpecificFailure(0x12)); ASSERT_EQ(ActionReturnStatus(CHIP_IM_GLOBAL_STATUS(Timeout)).GetStatusCode(), ClusterStatusCode(Status::Timeout)); } + +TEST(TestActionReturnStatus, TestCString) +{ + /// only tests the strings that we build and NOT the CHIP_ERROR ones which + /// are tested separately. for chip_error we just say it should not be empty. + ActionReturnStatus::StringStorage buffer; + ActionReturnStatus status(Status::Success); + + // chip-error returns something non-empty + status = CHIP_ERROR_NOT_FOUND; + ASSERT_STRNE(status.c_str(buffer), ""); + + status = CHIP_NO_ERROR; + ASSERT_STRNE(status.c_str(buffer), ""); + + // the items below we control +#if CHIP_CONFIG_IM_STATUS_CODE_VERBOSE_FORMAT + status = Status::Success; + ASSERT_STREQ(status.c_str(buffer), "SUCCESS(0)"); + + status = Status::UnsupportedCommand; + ASSERT_STREQ(status.c_str(buffer), "UNSUPPORTED_COMMAND(129)"); + + status = ClusterStatusCode::ClusterSpecificSuccess(31); + ASSERT_STREQ(status.c_str(buffer), "SUCCESS(0), Code 31"); + + status = ClusterStatusCode::ClusterSpecificFailure(32); + ASSERT_STREQ(status.c_str(buffer), "FAILURE(1), Code 32"); +#else + status = Status::Success; + ASSERT_STREQ(status.c_str(buffer), "Success"); + + status = Status::UnsupportedCommand; + ASSERT_STREQ(status.c_str(buffer), "Status<129>"); + + status = ClusterStatusCode::ClusterSpecificSuccess(31); + ASSERT_STREQ(status.c_str(buffer), "Success, Code 31"); + + status = ClusterStatusCode::ClusterSpecificFailure(32); + ASSERT_STREQ(status.c_str(buffer), "Status<1>, Code 32"); +#endif +} diff --git a/src/app/reporting/Read-Checked.cpp b/src/app/reporting/Read-Checked.cpp index cd821bc67ae4f6..2bb969aac094d2 100644 --- a/src/app/reporting/Read-Checked.cpp +++ b/src/app/reporting/Read-Checked.cpp @@ -82,12 +82,13 @@ ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataModel, const Ac if (statusEmber != statusDm) { - StringBuilder<128> buffer; + ActionReturnStatus::StringStorage buffer; + // Note log + chipDie instead of VerifyOrDie so that breakpoints (and usage of rr) // is easier to debug. ChipLogError(Test, "Different return codes between ember and DM"); - ChipLogError(Test, " Ember status: %s", statusEmber.c_str()); - ChipLogError(Test, " DM status: %s", statusDm.c_str()); + ChipLogError(Test, " Ember status: %s", statusEmber.c_str(buffer)); + ChipLogError(Test, " DM status: %s", statusDm.c_str(buffer)); // For time-dependent data, we may have size differences here: one data fitting in buffer // while another not, resulting in different errors (success vs out of space). diff --git a/src/app/reporting/Read-DataModel.cpp b/src/app/reporting/Read-DataModel.cpp index 7df19e2c89ecfc..b84d6586d2e2a0 100644 --- a/src/app/reporting/Read-DataModel.cpp +++ b/src/app/reporting/Read-DataModel.cpp @@ -95,7 +95,8 @@ DataModel::ActionReturnStatus RetrieveClusterData(DataModel::Provider * dataMode // and will be sent to the client as well). if (!status.IsOutOfSpaceEncodingResponse()) { - ChipLogError(DataManagement, "Failed to read attribute: %s", status.c_str()); + DataModel::ActionReturnStatus::StringStorage storage; + ChipLogError(DataManagement, "Failed to read attribute: %s", status.c_str(storage)); } return status; } From 49987b0e022cef72e3ce41e3d64dca711fd3b866 Mon Sep 17 00:00:00 2001 From: Vatsal Ghelani <152916324+vatsalghelani-csa@users.noreply.github.com> Date: Wed, 7 Aug 2024 10:28:09 -0400 Subject: [PATCH 34/41] Introduced a python script (execute_python_tests.py) that automates the execution of python test scripts within the python_testing directory (#34377) * Adding the python script to glob the python_testing folder on executing necessary tests * Removed the baed command temp file while inhertiing it from the tests.yaml script * Fixed the extra script execution part * Fixes to the script * Fixed the python script with correct command * Fixed the doyenv module not found error * Restyled by autopep8 * Restyled by isort * Fixed the script as per comments added to the code review * Restyled by autopep8 * Restyled by isort * Fixed the comment review * Restyled by autopep8 * Added the argument design patterns for TC_BOOLCFG* and TC_VALCC* scripts * Added --hex-arg as argument needed for TC_BOOLCFG tests * Revert "Added --hex-arg as argument needed for TC_BOOLCFG tests" This reverts commit 0764957d2855171a57fe5cbe2fe372ab2e0e6139. * Undo submodule change * Fixed the --hex-arg argument * Fixed arguments according to test requirement * Excluded new script added since it is run via python3 directly * Fixed .py of the exclusion script * Added fixes to the script arguments and new scripts run * Removed support test to run * REPL Tests - Linux run * Excluded recently added DEMTEst support python from all script execution * Excluded tests yet not ready for CI * Excluded the support test for TC_EWATERHTR * Excluded not ready tests * Fix file * Fix file comma formatting --------- Co-authored-by: Restyled.io --- .github/workflows/tests.yaml | 107 +---------------- src/python_testing/TC_ACL_2_2.py | 10 ++ src/python_testing/TC_BOOLCFG_2_1.py | 9 ++ src/python_testing/TC_BOOLCFG_3_1.py | 9 ++ src/python_testing/TC_BOOLCFG_4_1.py | 9 ++ src/python_testing/TC_BOOLCFG_4_2.py | 9 ++ src/python_testing/TC_BOOLCFG_4_3.py | 9 ++ src/python_testing/TC_BOOLCFG_4_4.py | 9 ++ src/python_testing/TC_BOOLCFG_5_1.py | 9 ++ src/python_testing/TC_BOOLCFG_5_2.py | 9 ++ src/python_testing/TC_VALCC_2_1.py | 9 ++ src/python_testing/TC_VALCC_3_1.py | 9 ++ src/python_testing/TC_VALCC_3_2.py | 9 ++ src/python_testing/TC_VALCC_3_3.py | 9 ++ src/python_testing/TC_VALCC_3_4.py | 9 ++ src/python_testing/TC_VALCC_4_1.py | 9 ++ src/python_testing/TC_VALCC_4_2.py | 9 ++ src/python_testing/TC_VALCC_4_3.py | 9 ++ src/python_testing/TC_VALCC_4_4.py | 9 ++ src/python_testing/TC_VALCC_4_5.py | 9 ++ src/python_testing/execute_python_tests.py | 128 +++++++++++++++++++++ 21 files changed, 301 insertions(+), 106 deletions(-) create mode 100644 src/python_testing/execute_python_tests.py diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 70f40efc502234..72080ea65ad772 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -506,112 +506,6 @@ jobs: run: | mkdir -p out/trace_data scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/controller/python/test/test_scripts/mobile-device-test.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ACE_1_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ACE_1_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ACE_1_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ACE_1_5.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_AccessChecker.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_CC_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_CC_10_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_CADMIN_1_9.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_CGEN_2_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_CNET_1_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DA_1_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DA_1_5.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DA_1_7.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DGGEN_2_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DRLK_2_12.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DRLK_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DRLK_2_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DeviceBasicComposition.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DeviceConformance.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_5.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_6.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_7.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_8.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_DEM_2_9.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEM_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEM_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEM_2_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEM_2_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEM_2_5.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEVSE_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEVSE_2_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEVSE_2_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EEVSE_2_5.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EPM_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_EPM_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_FAN_3_5.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ICDM_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ICDM_3_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ICDM_3_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_ICDManagementCluster.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_IDM_1_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_IDM_1_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_IDM_4_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_PWRTL_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RR_1_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_SC_3_6.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_2_10.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_2_11.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_2_12.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_2_13.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_2_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_2_5.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_2_6.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_2_7.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_2_8.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_2_9.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TIMESYNC_3_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_TestEventTrigger.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TestBatchInvoke.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TestGroupTableReports.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OCC_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OCC_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OCC_2_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OPCREDS_3_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OPCREDS_3_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OPSTATE_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OPSTATE_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OPSTATE_2_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OPSTATE_2_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OPSTATE_2_5.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OPSTATE_2_6.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OVENOPSTATE_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OVENOPSTATE_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OVENOPSTATE_2_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OVENOPSTATE_2_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_OVENOPSTATE_2_5.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_MWOCTRL_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_MWOCTRL_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_MWOCTRL_2_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_MWOM_1_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_PS_2_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCRUNM_1_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCRUNM_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCRUNM_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCCLEANM_1_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCCLEANM_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCCLEANM_2_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCOPSTATE_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCOPSTATE_2_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_RVCOPSTATE_2_4.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_SC_7_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_SWTCH.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_WHM_1_2.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_WHM_2_1.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TC_LVL_2_3.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --load-from-env /tmp/test_env.yaml --script src/python_testing/TCP_Tests.py' - scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestConformanceSupport.py" --script-args "--trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestMatterTestingSupport.py" --script-args "--trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TestSpecParsingSupport.py" --script-args "--trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' scripts/run_in_python_env.sh out/venv './scripts/tests/TestTimeSyncTrustedTimeSourceRunner.py' @@ -619,6 +513,7 @@ jobs: scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestIdChecks.py' scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestSpecParsingDeviceType.py' scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestConformanceSupport.py' + scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/TestChoiceConformanceSupport.py' scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/test_testing/test_IDM_10_4.py' scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/test_testing/test_TC_SC_7_1.py' scripts/run_in_python_env.sh out/venv 'python3 ./src/python_testing/test_testing/TestDecorators.py' diff --git a/src/python_testing/TC_ACL_2_2.py b/src/python_testing/TC_ACL_2_2.py index 252868a58d4ac3..a1e755b7397f88 100644 --- a/src/python_testing/TC_ACL_2_2.py +++ b/src/python_testing/TC_ACL_2_2.py @@ -14,6 +14,16 @@ # See the License for the specific language governing permissions and # limitations under the License. # + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import chip.clusters as Clusters from matter_testing_support import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts diff --git a/src/python_testing/TC_BOOLCFG_2_1.py b/src/python_testing/TC_BOOLCFG_2_1.py index d6ed97540056db..484d590b258b6d 100644 --- a/src/python_testing/TC_BOOLCFG_2_1.py +++ b/src/python_testing/TC_BOOLCFG_2_1.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import functools import logging from operator import ior diff --git a/src/python_testing/TC_BOOLCFG_3_1.py b/src/python_testing/TC_BOOLCFG_3_1.py index fb45e60ab38f8d..8e42140b35424c 100644 --- a/src/python_testing/TC_BOOLCFG_3_1.py +++ b/src/python_testing/TC_BOOLCFG_3_1.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging from random import choice diff --git a/src/python_testing/TC_BOOLCFG_4_1.py b/src/python_testing/TC_BOOLCFG_4_1.py index 74f81b7bfd79bd..3240c27ea219cc 100644 --- a/src/python_testing/TC_BOOLCFG_4_1.py +++ b/src/python_testing/TC_BOOLCFG_4_1.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import chip.clusters as Clusters diff --git a/src/python_testing/TC_BOOLCFG_4_2.py b/src/python_testing/TC_BOOLCFG_4_2.py index c0a74a9c46538a..b1496c49872fb0 100644 --- a/src/python_testing/TC_BOOLCFG_4_2.py +++ b/src/python_testing/TC_BOOLCFG_4_2.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --enable-key 000102030405060708090a0b0c0d0e0f --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --hex-arg PIXIT.BOOLCFG.TEST_EVENT_TRIGGER_KEY:000102030405060708090a0b0c0d0e0f --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import chip.clusters as Clusters diff --git a/src/python_testing/TC_BOOLCFG_4_3.py b/src/python_testing/TC_BOOLCFG_4_3.py index 90106efc2b8ab4..ea7ba2cac5f772 100644 --- a/src/python_testing/TC_BOOLCFG_4_3.py +++ b/src/python_testing/TC_BOOLCFG_4_3.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --enable-key 000102030405060708090a0b0c0d0e0f --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --hex-arg PIXIT.BOOLCFG.TEST_EVENT_TRIGGER_KEY:000102030405060708090a0b0c0d0e0f --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import chip.clusters as Clusters diff --git a/src/python_testing/TC_BOOLCFG_4_4.py b/src/python_testing/TC_BOOLCFG_4_4.py index b60ef12fd16f5f..2ae6dae2c763b4 100644 --- a/src/python_testing/TC_BOOLCFG_4_4.py +++ b/src/python_testing/TC_BOOLCFG_4_4.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --enable-key 000102030405060708090a0b0c0d0e0f --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --hex-arg PIXIT.BOOLCFG.TEST_EVENT_TRIGGER_KEY:000102030405060708090a0b0c0d0e0f --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import chip.clusters as Clusters diff --git a/src/python_testing/TC_BOOLCFG_5_1.py b/src/python_testing/TC_BOOLCFG_5_1.py index 90868fd8e6316c..f99fb3d8e48ca5 100644 --- a/src/python_testing/TC_BOOLCFG_5_1.py +++ b/src/python_testing/TC_BOOLCFG_5_1.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --enable-key 000102030405060708090a0b0c0d0e0f --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --hex-arg PIXIT.BOOLCFG.TEST_EVENT_TRIGGER_KEY:000102030405060708090a0b0c0d0e0f --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import chip.clusters as Clusters diff --git a/src/python_testing/TC_BOOLCFG_5_2.py b/src/python_testing/TC_BOOLCFG_5_2.py index 6e2657698a9d5c..cd176faf60574c 100644 --- a/src/python_testing/TC_BOOLCFG_5_2.py +++ b/src/python_testing/TC_BOOLCFG_5_2.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --enable-key 000102030405060708090a0b0c0d0e0f --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --hex-arg PIXIT.BOOLCFG.TEST_EVENT_TRIGGER_KEY:000102030405060708090a0b0c0d0e0f --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import chip.clusters as Clusters diff --git a/src/python_testing/TC_VALCC_2_1.py b/src/python_testing/TC_VALCC_2_1.py index c9f40d34694432..bb74f75d362e90 100644 --- a/src/python_testing/TC_VALCC_2_1.py +++ b/src/python_testing/TC_VALCC_2_1.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import chip.clusters as Clusters diff --git a/src/python_testing/TC_VALCC_3_1.py b/src/python_testing/TC_VALCC_3_1.py index 1b73976bdd9aae..e24c09db66c35d 100644 --- a/src/python_testing/TC_VALCC_3_1.py +++ b/src/python_testing/TC_VALCC_3_1.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import time import chip.clusters as Clusters diff --git a/src/python_testing/TC_VALCC_3_2.py b/src/python_testing/TC_VALCC_3_2.py index 1cd672f6a3ee2c..9ef0886d8b0cba 100644 --- a/src/python_testing/TC_VALCC_3_2.py +++ b/src/python_testing/TC_VALCC_3_2.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import time diff --git a/src/python_testing/TC_VALCC_3_3.py b/src/python_testing/TC_VALCC_3_3.py index d987516e67ccaa..ddf3ba83d1b5c7 100644 --- a/src/python_testing/TC_VALCC_3_3.py +++ b/src/python_testing/TC_VALCC_3_3.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import time diff --git a/src/python_testing/TC_VALCC_3_4.py b/src/python_testing/TC_VALCC_3_4.py index cef6bb81ee5ff0..906854011aceb3 100644 --- a/src/python_testing/TC_VALCC_3_4.py +++ b/src/python_testing/TC_VALCC_3_4.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import chip.clusters as Clusters diff --git a/src/python_testing/TC_VALCC_4_1.py b/src/python_testing/TC_VALCC_4_1.py index f9a1488ddf754d..183151af614893 100644 --- a/src/python_testing/TC_VALCC_4_1.py +++ b/src/python_testing/TC_VALCC_4_1.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import time import chip.clusters as Clusters diff --git a/src/python_testing/TC_VALCC_4_2.py b/src/python_testing/TC_VALCC_4_2.py index 85ee4f8d4d34ec..7e331f5f0fa33a 100644 --- a/src/python_testing/TC_VALCC_4_2.py +++ b/src/python_testing/TC_VALCC_4_2.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import time diff --git a/src/python_testing/TC_VALCC_4_3.py b/src/python_testing/TC_VALCC_4_3.py index d696464827c20f..cdb8c38ca7e286 100644 --- a/src/python_testing/TC_VALCC_4_3.py +++ b/src/python_testing/TC_VALCC_4_3.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import chip.clusters as Clusters diff --git a/src/python_testing/TC_VALCC_4_4.py b/src/python_testing/TC_VALCC_4_4.py index 95aa1743187ee7..4fd1692da370bf 100644 --- a/src/python_testing/TC_VALCC_4_4.py +++ b/src/python_testing/TC_VALCC_4_4.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import logging import chip.clusters as Clusters diff --git a/src/python_testing/TC_VALCC_4_5.py b/src/python_testing/TC_VALCC_4_5.py index 7dd21b89eead6e..b07f4281d1c7c6 100644 --- a/src/python_testing/TC_VALCC_4_5.py +++ b/src/python_testing/TC_VALCC_4_5.py @@ -15,6 +15,15 @@ # limitations under the License. # +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: run1 +# test-runner-run/run1/app: ${ALL_CLUSTERS_APP} +# test-runner-run/run1/factoryreset: True +# test-runner-run/run1/quiet: True +# test-runner-run/run1/app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# test-runner-run/run1/script-args: --storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:${TRACE_TEST_JSON}.json --trace-to perfetto:${TRACE_TEST_PERFETTO}.perfetto +# === END CI TEST ARGUMENTS === + import time import chip.clusters as Clusters diff --git a/src/python_testing/execute_python_tests.py b/src/python_testing/execute_python_tests.py new file mode 100644 index 00000000000000..61b650a8078693 --- /dev/null +++ b/src/python_testing/execute_python_tests.py @@ -0,0 +1,128 @@ +# +# Copyright (c) 2024 Project CHIP Authors +# All rights reserved. +# +# 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 argparse +import glob +import os +import subprocess + +# Function to load --app argument environment variables from a file + + +def load_env_from_yaml(file_path): + """ + Load environment variables from the specified YAML file. + + The YAML file contains key-value pairs that define --app environment variables + required for the test scripts to run. These variables configurations needed during the test execution. + + This function reads the YAML file and sets the environment variables + in the current process's environment using os.environ. + + Args: + file_path (str): The path to the YAML file containing the environment variables. + """ + with open(file_path, 'r') as file: + for line in file: + if line.strip(): # Skip empty lines + key, value = line.strip().split(': ', 1) + os.environ[key] = value + + +def main(search_directory, env_file): + # Determine the root directory of the CHIP project + chip_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) + + # Load environment variables from the specified file + load_env_from_yaml(env_file) + + # Define the base command to run tests + base_command = os.path.join(chip_root, "scripts/tests/run_python_test.py") + + # Define the files and patterns to exclude + excluded_patterns = { + "MinimalRepresentation.py", + "TC_CNET_4_4.py", + "TC_CCTRL_2_1.py", + "TC_CCTRL_2_2.py", + "TC_DGGEN_3_2.py", + "TC_EEVSE_Utils.py", + "TC_ECOINFO_2_1.py", + "TC_ECOINFO_2_2.py", + "TC_EWATERHTRBase.py", + "TC_EnergyReporting_Utils.py", + "TC_OpstateCommon.py", + "TC_pics_checker.py", + "TC_TMP_2_1.py", + "TC_MCORE_FS_1_1.py", + "TC_MCORE_FS_1_2.py", + "TC_MCORE_FS_1_3.py", + "TC_BRBINFO_4_1.py", + "TestCommissioningTimeSync.py", + "TestConformanceSupport.py", + "TestChoiceConformanceSupport.py", + "TC_DEMTestBase.py", + "choice_conformance_support.py", + "TestIdChecks.py", + "TestSpecParsingDeviceType.py", + "TestMatterTestingSupport.py", + "TestSpecParsingSupport.py", + "TestTimeSyncTrustedTimeSource.py", + "basic_composition_support.py", + "conformance_support.py", + "drlk_2_x_common.py", + "execute_python_tests.py", + "global_attribute_ids.py", + "hello_external_runner.py", + "hello_test.py", + "matter_testing_support.py", + "pics_support.py", + "spec_parsing_support.py", + "taglist_and_topology_test_support.py", + "test_plan_support.py", + "test_plan_table_generator.py" + } + + """ + Explanation for excluded files: + The above list of files are excluded from the tests as they are either not app-specific tests + or are run through a different block of tests mentioned in tests.yaml. + This is to ensure that only relevant test scripts are executed, avoiding redundancy and ensuring + the correctness of the test suite. + """ + + # Get all .py files in the directory + all_python_files = glob.glob(os.path.join(search_directory, "*.py")) + + # Filter out the files matching the excluded patterns + python_files = [file for file in all_python_files if os.path.basename(file) not in excluded_patterns] + + # Run each script with the base command + for script in python_files: + full_command = f"{base_command} --load-from-env {env_file} --script {script}" + print(f"Running command: {full_command}") + subprocess.run(full_command, shell=True, check=True) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Run Python test scripts.") + parser.add_argument("--search-directory", type=str, default="src/python_testing", + help="Directory to search for Python scripts.") + parser.add_argument("--env-file", type=str, default="/tmp/test_env.yaml", help="Path to the environment variables file.") + + args = parser.parse_args() + main(args.search_directory, args.env_file) From 09925c337107dffebf19b368971bc16f7c967359 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 7 Aug 2024 11:07:58 -0400 Subject: [PATCH 35/41] Mark some immutable types in Matter.framework as NS_SWIFT_SENDABLE. (#34787) --- src/darwin/Framework/CHIP/MTRBaseDevice.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/darwin/Framework/CHIP/MTRBaseDevice.h b/src/darwin/Framework/CHIP/MTRBaseDevice.h index aa3efc54d578cb..d3a1b0833f11fd 100644 --- a/src/darwin/Framework/CHIP/MTRBaseDevice.h +++ b/src/darwin/Framework/CHIP/MTRBaseDevice.h @@ -164,6 +164,7 @@ typedef NS_ENUM(uint8_t, MTRTransportType) { * * nil is used to represent wildcards. */ +NS_SWIFT_SENDABLE MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) @interface MTRAttributeRequestPath : NSObject @property (nonatomic, readonly, copy, nullable) NSNumber * endpoint MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)); @@ -182,6 +183,7 @@ MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) * * nil is used to represent wildcards. */ +NS_SWIFT_SENDABLE MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) @interface MTREventRequestPath : NSObject @property (nonatomic, readonly, copy, nullable) NSNumber * endpoint MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)); @@ -572,6 +574,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) * A path indicating a specific cluster on a device (i.e. without any * wildcards). */ +NS_SWIFT_SENDABLE MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) @interface MTRClusterPath : NSObject @@ -588,6 +591,7 @@ MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) * A path indicating a specific attribute on a device (i.e. without any * wildcards). */ +NS_SWIFT_SENDABLE MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @interface MTRAttributePath : MTRClusterPath @@ -604,6 +608,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) * (i.e. without any wildcards). There can be multiple instances of actual * events for a given event path. */ +NS_SWIFT_SENDABLE MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @interface MTREventPath : MTRClusterPath @@ -618,6 +623,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) * A path indicating a specific command on a device (i.e. without any * wildcards). */ +NS_SWIFT_SENDABLE MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @interface MTRCommandPath : MTRClusterPath @@ -628,6 +634,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) commandID:(NSNumber *)commandID MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); @end +NS_SWIFT_SENDABLE MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @interface MTRAttributeReport : NSObject @@ -640,7 +647,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) * * The attribute is nullable and the value of the attribute is null. * * If value is not nil, the actual type of value will depend on the - * schema-defined (typically defiend in the Matter specification) type of the + * schema-defined (typically defined in the Matter specification) type of the * attribute as follows: * * * list: NSArray of whatever type the list entries are. @@ -697,6 +704,7 @@ typedef NS_ENUM(NSUInteger, MTREventPriority) { MTREventPriorityCritical = 2 } MTR_AVAILABLE(ios(16.5), macos(13.4), watchos(9.5), tvos(16.5)); +NS_SWIFT_SENDABLE MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @interface MTREventReport : NSObject From 4e2245bbe66b7ce91303bd76071f3bc5c6ffdd1e Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Wed, 7 Aug 2024 11:32:30 -0400 Subject: [PATCH 36/41] ECOINFO address post merge comment for small fix (#34846) --- .../ecosystem-information-server.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp index 74a27f21779ff9..b962150e219c63 100644 --- a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp +++ b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp @@ -282,11 +282,11 @@ CHIP_ERROR EcosystemInformationServer::ReadAttribute(const ConcreteReadAttribute switch (aPath.mAttributeId) { case Attributes::RemovedOn::Id: - return EcosystemInformationServer::Instance().EncodeRemovedOnAttribute(aPath.mEndpointId, aEncoder); + return EncodeRemovedOnAttribute(aPath.mEndpointId, aEncoder); case Attributes::DeviceDirectory::Id: - return EcosystemInformationServer::Instance().EncodeDeviceDirectoryAttribute(aPath.mEndpointId, aEncoder); + return EncodeDeviceDirectoryAttribute(aPath.mEndpointId, aEncoder); case Attributes::LocationDirectory::Id: - return EcosystemInformationServer::Instance().EncodeLocationStructAttribute(aPath.mEndpointId, aEncoder); + return EncodeLocationStructAttribute(aPath.mEndpointId, aEncoder); case Attributes::ClusterRevision::Id: { uint16_t rev = ZCL_ECOSYSTEM_INFORMATION_CLUSTER_REVISION; return aEncoder.Encode(rev); From a0fac9fd316cb63402430401bba7d4fe245b4efd Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Wed, 7 Aug 2024 12:58:02 -0400 Subject: [PATCH 37/41] Fabric Bridge: use AttributeAccessInterface for BridgedDeviceBasicInformationCluster, expose more attributes (#34845) * Add extra attributes to the bridged device basic info structures, remove nonsense comments * Make use of AAI for BridgedDeviceBasicInformation cluster * Restyled by gn * Fix sizes for software version * Bump revision to 4 --------- Co-authored-by: Restyled.io --- .../fabric-bridge-common/BUILD.gn | 2 + .../BridgedDeviceBasicInformationImpl.h | 32 ++++++++ .../src/BridgedDeviceBasicInformationImpl.cpp | 78 +++++++++++++++++++ .../src/BridgedDeviceManager.cpp | 52 +++++++++---- .../fabric-bridge-common/src/ZCLCallbacks.cpp | 64 +-------------- examples/fabric-bridge-app/linux/main.cpp | 4 + 6 files changed, 154 insertions(+), 78 deletions(-) create mode 100644 examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceBasicInformationImpl.h create mode 100644 examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp diff --git a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn index 10cb48c31c584e..38f2f8f329bd88 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn +++ b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn @@ -30,9 +30,11 @@ source_set("fabric-bridge-lib") { sources = [ "include/BridgedDevice.h", + "include/BridgedDeviceBasicInformationImpl.h", "include/BridgedDeviceManager.h", "include/CHIPProjectAppConfig.h", "src/BridgedDevice.cpp", + "src/BridgedDeviceBasicInformationImpl.cpp", "src/BridgedDeviceManager.cpp", "src/ZCLCallbacks.cpp", ] diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceBasicInformationImpl.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceBasicInformationImpl.h new file mode 100644 index 00000000000000..23403438ab2be8 --- /dev/null +++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceBasicInformationImpl.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024 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. + */ +#pragma once + +#include +#include + +class BridgedDeviceBasicInformationImpl : public chip::app::AttributeAccessInterface +{ +public: + BridgedDeviceBasicInformationImpl() : + chip::app::AttributeAccessInterface(chip::NullOptional /* endpointId */, + chip::app::Clusters::BridgedDeviceBasicInformation::Id) + {} + + // AttributeAccessInterface implementation + CHIP_ERROR Read(const chip::app::ConcreteReadAttributePath & path, chip::app::AttributeValueEncoder & encoder) override; + CHIP_ERROR Write(const chip::app::ConcreteDataAttributePath & path, chip::app::AttributeValueDecoder & decoder) override; +}; diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp new file mode 100644 index 00000000000000..62630d730b4355 --- /dev/null +++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024 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. + */ +#include "BridgedDeviceBasicInformationImpl.h" + +#include "BridgedDeviceManager.h" + +#include +#include +#include + +#include + +static constexpr unsigned kBridgedDeviceBasicInformationClusterRevision = 4; +static constexpr unsigned kBridgedDeviceBasicInformationFeatureMap = 0; + +using namespace ::chip; +using namespace ::chip::app; +using namespace ::chip::app::Clusters; + +CHIP_ERROR BridgedDeviceBasicInformationImpl::Read(const ConcreteReadAttributePath & path, AttributeValueEncoder & encoder) +{ + // Registration is done for the bridged device basic information only + VerifyOrDie(path.mClusterId == app::Clusters::BridgedDeviceBasicInformation::Id); + + BridgedDevice * dev = BridgeDeviceMgr().GetDevice(path.mEndpointId); + VerifyOrReturnError(dev != nullptr, CHIP_ERROR_NOT_FOUND); + + switch (path.mAttributeId) + { + case BasicInformation::Attributes::Reachable::Id: + encoder.Encode(dev->IsReachable()); + break; + case BasicInformation::Attributes::NodeLabel::Id: + encoder.Encode(CharSpan::fromCharString(dev->GetName())); + break; + case BasicInformation::Attributes::ClusterRevision::Id: + encoder.Encode(kBridgedDeviceBasicInformationClusterRevision); + break; + case BasicInformation::Attributes::FeatureMap::Id: + encoder.Encode(kBridgedDeviceBasicInformationFeatureMap); + break; + default: + return CHIP_ERROR_INVALID_ARGUMENT; + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR BridgedDeviceBasicInformationImpl::Write(const ConcreteDataAttributePath & path, AttributeValueDecoder & decoder) +{ + VerifyOrDie(path.mClusterId == app::Clusters::BridgedDeviceBasicInformation::Id); + + BridgedDevice * dev = BridgeDeviceMgr().GetDevice(path.mEndpointId); + VerifyOrReturnError(dev != nullptr, CHIP_ERROR_NOT_FOUND); + + if (!dev->IsReachable()) + { + return CHIP_ERROR_NOT_CONNECTED; + } + + ChipLogProgress(NotSpecified, "Bridged device basic information attempt to write attribute: ep=%d", path.mAttributeId); + + // nothing writable right now ... + + return CHIP_ERROR_INVALID_ARGUMENT; +} diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp index 170b39cd2c94e2..7e78baa7ded548 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp +++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp @@ -45,8 +45,13 @@ using namespace chip::app::Clusters; namespace { -constexpr uint8_t kMaxRetries = 10; -constexpr int kNodeLabelSize = 32; +constexpr uint8_t kMaxRetries = 10; +constexpr int kNodeLabelSize = 32; +constexpr int kUniqueIdSize = 32; +constexpr int kVendorNameSize = 32; +constexpr int kProductNameSize = 32; +constexpr int kHardwareVersionSize = 32; +constexpr int kSoftwareVersionSize = 32; // Current ZCL implementation of Struct uses a max-size array of 254 bytes constexpr int kDescriptorAttributeArraySize = 254; @@ -76,27 +81,44 @@ constexpr int kDescriptorAttributeArraySize = 254; // - Bridged Device Basic Information // - Administrator Commissioning +// clang-format off // Declare Descriptor cluster attributes DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(descriptorAttrs) -DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::DeviceTypeList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* device list */ - DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ServerList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* server list */ - DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ClientList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* client list */ - DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::PartsList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* parts list */ - DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::DeviceTypeList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* device list */ + DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ServerList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* server list */ + DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ClientList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* client list */ + DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::PartsList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* parts list */ +DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); // Declare Bridged Device Basic Information cluster attributes DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(bridgedDeviceBasicAttrs) -DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::NodeLabel::Id, CHAR_STRING, kNodeLabelSize, 0), /* NodeLabel */ - DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::Reachable::Id, BOOLEAN, 1, 0), /* Reachable */ - DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* feature map */ - DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + // The attributes below are MANDATORY in the Bridged Device Information Cluster + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::Reachable::Id, BOOLEAN, 1, 0), + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::UniqueID::Id, CHAR_STRING, kUniqueIdSize, 0), + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::FeatureMap::Id, BITMAP32, 4, 0), + + // The attributes below are OPTIONAL in the bridged device, however they are MANDATORY in the BasicInformation cluster + // so they can always be provided if desired + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::VendorName::Id, CHAR_STRING, kVendorNameSize, 0), + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::VendorID::Id, INT16U, 2, 0), + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::ProductName::Id, CHAR_STRING, kProductNameSize, 0), + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::ProductID::Id, INT16U, 2, 0), + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::NodeLabel::Id, CHAR_STRING, kNodeLabelSize, 0), + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::HardwareVersion::Id, INT16U, 2, 0), + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::HardwareVersionString::Id, CHAR_STRING, + kHardwareVersionSize, 0), + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::SoftwareVersion::Id, INT32U, 4, 0), + DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::SoftwareVersionString::Id, CHAR_STRING, + kSoftwareVersionSize, 0), +DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); // Declare Administrator Commissioning cluster attributes DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(AdministratorCommissioningAttrs) -DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::WindowStatus::Id, ENUM8, 1, 0), /* NodeLabel */ - DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminFabricIndex::Id, FABRIC_IDX, 1, 0), /* Reachable */ - DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminVendorId::Id, VENDOR_ID, 2, 0), /* Reachable */ - DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::WindowStatus::Id, ENUM8, 1, 0), + DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminFabricIndex::Id, FABRIC_IDX, 1, 0), + DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminVendorId::Id, VENDOR_ID, 2, 0), +DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); +// clang-format on constexpr CommandId administratorCommissioningCommands[] = { app::Clusters::AdministratorCommissioning::Commands::OpenCommissioningWindow::Id, diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp index 26e727901abf0e..d4da982cfa45a5 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp +++ b/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp @@ -25,88 +25,26 @@ using namespace ::chip; using namespace ::chip::app::Clusters; -#define ZCL_DESCRIPTOR_CLUSTER_REVISION (1u) #define ZCL_ADMINISTRATOR_COMMISSIONING_CLUSTER_REVISION (1u) -#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION (2u) -#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP (0u) // External attribute read callback function Protocols::InteractionModel::Status emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId, const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer, uint16_t maxReadLength) { - AttributeId attributeId = attributeMetadata->attributeId; - - BridgedDevice * dev = BridgeDeviceMgr().GetDevice(endpoint); - if (dev == nullptr) - { - return Protocols::InteractionModel::Status::Failure; - } - - if (clusterId == BridgedDeviceBasicInformation::Id) - { - using namespace BridgedDeviceBasicInformation::Attributes; - ChipLogProgress(NotSpecified, "HandleReadBridgedDeviceBasicAttribute: attrId=%d, maxReadLength=%d", attributeId, - maxReadLength); - - if ((attributeId == Reachable::Id) && (maxReadLength == 1)) - { - *buffer = dev->IsReachable() ? 1 : 0; - } - else if ((attributeId == NodeLabel::Id) && (maxReadLength == 32)) - { - MutableByteSpan zclNameSpan(buffer, maxReadLength); - MakeZclCharString(zclNameSpan, dev->GetName()); - } - else if ((attributeId == ClusterRevision::Id) && (maxReadLength == 2)) - { - uint16_t rev = ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION; - memcpy(buffer, &rev, sizeof(rev)); - } - else if ((attributeId == FeatureMap::Id) && (maxReadLength == 4)) - { - uint32_t featureMap = ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP; - memcpy(buffer, &featureMap, sizeof(featureMap)); - } - else - { - return Protocols::InteractionModel::Status::Failure; - } - return Protocols::InteractionModel::Status::Success; - } - if (clusterId == AdministratorCommissioning::Id) { // TODO(#34791) This is a workaround to prevent crash. CADMIN is still reading incorrect // Attribute values on dynamic endpoint as it only reads the root node and not the actual bridge // device we are representing here, when addressing the issue over there we can more easily // resolve this workaround. - if ((attributeId == AdministratorCommissioning::Attributes::ClusterRevision::Id) && (maxReadLength == 2)) + if ((attributeMetadata->attributeId == AdministratorCommissioning::Attributes::ClusterRevision::Id) && (maxReadLength == 2)) { uint16_t rev = ZCL_ADMINISTRATOR_COMMISSIONING_CLUSTER_REVISION; memcpy(buffer, &rev, sizeof(rev)); return Protocols::InteractionModel::Status::Success; } - return Protocols::InteractionModel::Status::Failure; } return Protocols::InteractionModel::Status::Failure; } - -// External attribute write callback function -Protocols::InteractionModel::Status emberAfExternalAttributeWriteCallback(EndpointId endpoint, ClusterId clusterId, - const EmberAfAttributeMetadata * attributeMetadata, - uint8_t * buffer) -{ - uint16_t endpointIndex = emberAfGetDynamicIndexFromEndpoint(endpoint); - Protocols::InteractionModel::Status ret = Protocols::InteractionModel::Status::Failure; - - BridgedDevice * dev = BridgeDeviceMgr().GetDevice(endpointIndex); - if (dev != nullptr && dev->IsReachable()) - { - ChipLogProgress(NotSpecified, "emberAfExternalAttributeWriteCallback: ep=%d, clusterId=%d", endpoint, clusterId); - ret = Protocols::InteractionModel::Status::Success; - } - - return ret; -} diff --git a/examples/fabric-bridge-app/linux/main.cpp b/examples/fabric-bridge-app/linux/main.cpp index c708b256727520..24ad4aa9a1690c 100644 --- a/examples/fabric-bridge-app/linux/main.cpp +++ b/examples/fabric-bridge-app/linux/main.cpp @@ -19,6 +19,7 @@ #include #include "BridgedDevice.h" +#include "BridgedDeviceBasicInformationImpl.h" #include "BridgedDeviceManager.h" #include "CommissionableInit.h" @@ -48,6 +49,8 @@ constexpr uint16_t kPollIntervalMs = 100; constexpr uint16_t kRetryIntervalS = 3; #endif +BridgedDeviceBasicInformationImpl gBridgedDeviceBasicInformationAttributes; + bool KeyboardHit() { int bytesWaiting; @@ -175,6 +178,7 @@ void ApplicationInit() ChipLogDetail(NotSpecified, "Fabric-Bridge: ApplicationInit()"); CommandHandlerInterfaceRegistry::RegisterCommandHandler(&gAdministratorCommissioningCommandHandler); + registerAttributeAccessOverride(&gBridgedDeviceBasicInformationAttributes); #if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE InitRpcServer(kFabricBridgeServerPort); From e8186eb0637a02fa094eaf68eb7b8e5774797511 Mon Sep 17 00:00:00 2001 From: Terence Hampson Date: Wed, 7 Aug 2024 13:00:21 -0400 Subject: [PATCH 38/41] fabric-bridge: Add ECOINFO to dynamic bridged endpoints (#34811) --------- Co-authored-by: Restyled.io Co-authored-by: saurabhst --- .../fabric-bridge-common/BUILD.gn | 14 ++++++++++++- .../src/BridgedDeviceManager.cpp | 8 ++++++++ .../fabric-bridge-app/linux/RpcServer.cpp | 5 +++++ examples/fabric-bridge-app/linux/main.cpp | 11 +++++++++- .../ecosystem-information-server.cpp | 11 ++++++++++ .../ecosystem-information-server.h | 20 ++++++++++++++++++- 6 files changed, 66 insertions(+), 3 deletions(-) diff --git a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn index 38f2f8f329bd88..7f2fbcbbfe0556 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn +++ b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn @@ -19,12 +19,24 @@ config("config") { include_dirs = [ "include" ] } -chip_data_model("fabric-bridge-common") { +chip_data_model("fabric-bridge-common-zap") { zap_file = "fabric-bridge-app.zap" is_server = true cflags = [ "-DDYNAMIC_ENDPOINT_COUNT=16" ] } +# This includes all the clusters that only exist on the dynamic endpoint. +source_set("fabric-bridge-common") { + public_configs = [ ":config" ] + + sources = [ + "${chip_root}/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp", + "${chip_root}/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h", + ] + + public_deps = [ ":fabric-bridge-common-zap" ] +} + source_set("fabric-bridge-lib") { public_configs = [ ":config" ] diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp index 7e78baa7ded548..64b88e49bb5c96 100644 --- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp +++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp @@ -112,6 +112,13 @@ DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(bridgedDeviceBasicAttrs) kSoftwareVersionSize, 0), DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); +// Declare Ecosystem Information cluster attributes +DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(ecosystemInformationBasicAttrs) +DECLARE_DYNAMIC_ATTRIBUTE(EcosystemInformation::Attributes::RemovedOn::Id, EPOCH_US, kNodeLabelSize, ATTRIBUTE_MASK_NULLABLE), + DECLARE_DYNAMIC_ATTRIBUTE(EcosystemInformation::Attributes::DeviceDirectory::Id, ARRAY, kDescriptorAttributeArraySize, 0), + DECLARE_DYNAMIC_ATTRIBUTE(EcosystemInformation::Attributes::LocationDirectory::Id, ARRAY, kDescriptorAttributeArraySize, 0), + DECLARE_DYNAMIC_ATTRIBUTE_LIST_END(); + // Declare Administrator Commissioning cluster attributes DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(AdministratorCommissioningAttrs) DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::WindowStatus::Id, ENUM8, 1, 0), @@ -131,6 +138,7 @@ constexpr CommandId administratorCommissioningCommands[] = { DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedNodeClusters) DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), + DECLARE_DYNAMIC_CLUSTER(EcosystemInformation::Id, ecosystemInformationBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr), DECLARE_DYNAMIC_CLUSTER(AdministratorCommissioning::Id, AdministratorCommissioningAttrs, ZAP_CLUSTER_MASK(SERVER), administratorCommissioningCommands, nullptr) DECLARE_DYNAMIC_CLUSTER_LIST_END; diff --git a/examples/fabric-bridge-app/linux/RpcServer.cpp b/examples/fabric-bridge-app/linux/RpcServer.cpp index 76fe8f84653d39..a4053bea9f6a56 100644 --- a/examples/fabric-bridge-app/linux/RpcServer.cpp +++ b/examples/fabric-bridge-app/linux/RpcServer.cpp @@ -20,6 +20,7 @@ #include "pw_rpc_system_server/rpc_server.h" #include "pw_rpc_system_server/socket.h" +#include #include #include @@ -62,6 +63,10 @@ pw::Status FabricBridge::AddSynchronizedDevice(const chip_rpc_SynchronizedDevice return pw::Status::Unknown(); } + CHIP_ERROR err = EcosystemInformation::EcosystemInformationServer::Instance().AddEcosystemInformationClusterToEndpoint( + device->GetEndpointId()); + VerifyOrDie(err == CHIP_NO_ERROR); + return pw::OkStatus(); } diff --git a/examples/fabric-bridge-app/linux/main.cpp b/examples/fabric-bridge-app/linux/main.cpp index 24ad4aa9a1690c..4f227b1f4a0436 100644 --- a/examples/fabric-bridge-app/linux/main.cpp +++ b/examples/fabric-bridge-app/linux/main.cpp @@ -25,6 +25,7 @@ #include #include +#include #if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE #include "RpcClient.h" @@ -35,8 +36,15 @@ #include #include -using namespace chip; +// This is declared here and not in a header because zap/embr assumes all clusters +// are defined in a static endpoint in the .zap file. From there, the codegen will +// automatically use PluginApplicationCallbacksHeader.jinja to declare and call +// the respective Init callbacks. However, because EcosystemInformation cluster is only +// ever on a dynamic endpoint, this doesn't get declared and called for us, so we +// need to declare and call it ourselves where the application is initialized. +void MatterEcosystemInformationPluginServerInitCallback(); +using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; using namespace chip::app::Clusters::AdministratorCommissioning; @@ -177,6 +185,7 @@ void ApplicationInit() { ChipLogDetail(NotSpecified, "Fabric-Bridge: ApplicationInit()"); + MatterEcosystemInformationPluginServerInitCallback(); CommandHandlerInterfaceRegistry::RegisterCommandHandler(&gAdministratorCommissioningCommandHandler); registerAttributeAccessOverride(&gBridgedDeviceBasicInformationAttributes); diff --git a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp index b962150e219c63..9d82f7064f0f1b 100644 --- a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp +++ b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.cpp @@ -243,6 +243,17 @@ EcosystemInformationServer & EcosystemInformationServer::Instance() return mInstance; } +CHIP_ERROR EcosystemInformationServer::AddEcosystemInformationClusterToEndpoint(EndpointId aEndpoint) +{ + VerifyOrReturnError((aEndpoint != kRootEndpointId && aEndpoint != kInvalidEndpointId), CHIP_ERROR_INVALID_ARGUMENT); + auto it = mDevicesMap.find(aEndpoint); + // We expect that the device has not been previously added. + VerifyOrReturnError((it == mDevicesMap.end()), CHIP_ERROR_INCORRECT_STATE); + // This create an empty DeviceInfo in mDevicesMap. + mDevicesMap[aEndpoint] = DeviceInfo(); + return CHIP_NO_ERROR; +} + CHIP_ERROR EcosystemInformationServer::AddDeviceInfo(EndpointId aEndpoint, std::unique_ptr aDevice) { VerifyOrReturnError(aDevice, CHIP_ERROR_INVALID_ARGUMENT); diff --git a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h index daa6f0124d9e39..dce12e745bf14e 100644 --- a/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h +++ b/src/app/clusters/ecosystem-information-server/ecosystem-information-server.h @@ -150,6 +150,24 @@ class EcosystemInformationServer public: static EcosystemInformationServer & Instance(); + /** + * @brief Add EcosystemInformation Cluster to endpoint so we respond appropriately on endpoint + * + * EcosystemInformation cluster is only ever on dynamic bridge endpoint. If cluster is added + * to a new endpoint, but does not contain any ecosystem information presently, + * this is called to let ECOINFO cluster code know it is supposed to provide blank attribute + * information on this endpoint. + * + * This approach was intentionally taken instead of relying on emberAfDeviceTypeListFromEndpoint + * to keep this cluster more unit testable. This does add burden to application but is worth + * the trade-off. + * + * @param[in] aEndpoint Which endpoint is the device being added to the device directory. + * @return #CHIP_NO_ERROR on success. + * @return Other CHIP_ERROR associated with issue. + */ + CHIP_ERROR AddEcosystemInformationClusterToEndpoint(EndpointId aEndpoint); + /** * @brief Adds device as entry to DeviceDirectory list Attribute. * @@ -187,7 +205,7 @@ class EcosystemInformationServer private: struct DeviceInfo { - Optional mRemovedOn; + Optional mRemovedOn = NullOptional; std::vector> mDeviceDirectory; // Map key is using the UniqueLocationId std::map> mLocationDirectory; From d47c423421defba422683984489fad9d78ae0097 Mon Sep 17 00:00:00 2001 From: Praveen Chandran Date: Wed, 7 Aug 2024 10:18:25 -0700 Subject: [PATCH 39/41] [Infineon] Update ModusToolbox version to 3.2 along with README.md update (#34681) Co-authored-by: Andrei Litvin --- .../all-clusters-app/infineon/psoc6/README.md | 10 ++++--- .../infineon/psoc6/README.md | 10 ++++--- .../lighting-app/infineon/psoc6/README.md | 12 ++++---- examples/lock-app/infineon/psoc6/README.md | 20 +++++++------ .../docker/images/base/chip-build/version | 2 +- .../stage-2/chip-build-infineon/Dockerfile | 28 ++++++++++--------- .../vscode/chip-build-vscode/Dockerfile | 6 ++-- scripts/examples/gn_psoc6_example.sh | 23 +++++---------- 8 files changed, 56 insertions(+), 55 deletions(-) diff --git a/examples/all-clusters-app/infineon/psoc6/README.md b/examples/all-clusters-app/infineon/psoc6/README.md index 75a01995d8c9e4..138f132f7a0dba 100644 --- a/examples/all-clusters-app/infineon/psoc6/README.md +++ b/examples/all-clusters-app/infineon/psoc6/README.md @@ -30,10 +30,11 @@ will then join the network. ## Building -- [Modustoolbox Software](https://www.cypress.com/products/modustoolbox) +- Download and install + [Modustoolbox Software v3.2](https://www.infineon.com/modustoolbox) - Refer to `integrations/docker/images/chip-build-infineon/Dockerfile` or - `scripts/examples/gn_psoc6_example.sh` for downloading the Software and + Refer to `integrations/docker/images/stage-2/chip-build-infineon/Dockerfile` + or `scripts/examples/gn_psoc6_example.sh` for downloading the Software and related tools. - Install some additional tools (likely already present for Matter @@ -62,11 +63,12 @@ will then join the network. - Put CY8CKIT-062S2-43012 board on KitProg3 CMSIS-DAP Mode by pressing the `MODE SELECT` button. `KITPROG3 STATUS` LED is ON confirms board is in - proper mode. + proper mode. (Modustoolbox Software needs to be installed) - On the command line: $ cd ~/connectedhomeip + $ export CY_TOOLS_PATHS=/tools_3.2 $ python3 out/infineon-psoc6-all-clusters/chip-psoc6-clusters-example.flash.py ## Commissioning and cluster control diff --git a/examples/all-clusters-minimal-app/infineon/psoc6/README.md b/examples/all-clusters-minimal-app/infineon/psoc6/README.md index 4ebd3832f43de6..80b8e1ceb66791 100644 --- a/examples/all-clusters-minimal-app/infineon/psoc6/README.md +++ b/examples/all-clusters-minimal-app/infineon/psoc6/README.md @@ -30,10 +30,11 @@ will then join the network. ## Building -- [Modustoolbox Software](https://www.cypress.com/products/modustoolbox) +- Download and install + [Modustoolbox Software v3.2](https://www.infineon.com/modustoolbox) - Refer to `integrations/docker/images/chip-build-infineon/Dockerfile` or - `scripts/examples/gn_psoc6_example.sh` for downloading the Software and + Refer to `integrations/docker/images/stage-2/chip-build-infineon/Dockerfile` + or `scripts/examples/gn_psoc6_example.sh` for downloading the Software and related tools. - Install some additional tools (likely already present for Matter @@ -62,11 +63,12 @@ will then join the network. - Put CY8CKIT-062S2-43012 board on KitProg3 CMSIS-DAP Mode by pressing the `MODE SELECT` button. `KITPROG3 STATUS` LED is ON confirms board is in - proper mode. + proper mode. (Modustoolbox Software needs to be installed) - On the command line: $ cd ~/connectedhomeip + $ export CY_TOOLS_PATHS=/tools_3.2 $ python3 out/infineon-psoc6-all-clusters-minimal/chip-psoc6-clusters-minimal-example.flash.py ## Commissioning and cluster control diff --git a/examples/lighting-app/infineon/psoc6/README.md b/examples/lighting-app/infineon/psoc6/README.md index e5b5854fc275e5..773a05af1f3899 100644 --- a/examples/lighting-app/infineon/psoc6/README.md +++ b/examples/lighting-app/infineon/psoc6/README.md @@ -31,10 +31,11 @@ will then join the network. ## Building -- [Modustoolbox Software](https://www.cypress.com/products/modustoolbox) +- Download and install + [Modustoolbox Software v3.2](https://www.infineon.com/modustoolbox) - Refer to `integrations/docker/images/chip-build-infineon/Dockerfile` or - `scripts/examples/gn_psoc6_example.sh` for downloading the Software and + Refer to `integrations/docker/images/stage-2/chip-build-infineon/Dockerfile` + or `scripts/examples/gn_psoc6_example.sh` for downloading the Software and related tools. - Install some additional tools (likely already present for Matter @@ -43,7 +44,7 @@ will then join the network. python3-pip - Supported hardware: - [CY8CKIT-062S2-43012](https://www.cypress.com/CY8CKIT-062S2-43012) + [CY8CKIT-062S2-43012](https://www.infineon.com/CY8CKIT-062S2-43012) * Build the example application: @@ -59,11 +60,12 @@ will then join the network. - Put CY8CKIT-062S2-43012 board on KitProg3 CMSIS-DAP Mode by pressing the `MODE SELECT` button. `KITPROG3 STATUS` LED is ON confirms board is in - proper mode. + proper mode. (Modustoolbox Software needs to be installed) - On the command line: $ cd ~/connectedhomeip + $ export CY_TOOLS_PATHS=/tools_3.2 $ python3 out/infineon-psoc6-light/chip-psoc6-lighting-example.flash.py ## Commissioning and cluster control diff --git a/examples/lock-app/infineon/psoc6/README.md b/examples/lock-app/infineon/psoc6/README.md index b1e1e1a0e9ac6b..0c8e8eb1e8c781 100644 --- a/examples/lock-app/infineon/psoc6/README.md +++ b/examples/lock-app/infineon/psoc6/README.md @@ -33,10 +33,11 @@ will then join the network. ## Building -- [Modustoolbox Software](https://www.cypress.com/products/modustoolbox) +- Download and install + [Modustoolbox Software v3.2](https://www.infineon.com/modustoolbox) - Refer to `integrations/docker/images/chip-build-infineon/Dockerfile` or - `scripts/examples/gn_psoc6_example.sh` for downloading the Software and + Refer to `integrations/docker/images/stage-2/chip-build-infineon/Dockerfile` + or `scripts/examples/gn_psoc6_example.sh` for downloading the Software and related tools. - Install some additional tools (likely already present for Matter @@ -45,7 +46,7 @@ will then join the network. python3-pip - Supported hardware: - [CY8CKIT-062S2-43012](https://www.cypress.com/CY8CKIT-062S2-43012) + [CY8CKIT-062S2-43012](https://www.infineon.com/CY8CKIT-062S2-43012) * Build the example application: @@ -66,11 +67,12 @@ more instructions_ - Put CY8CKIT-062S2-43012 board on KitProg3 CMSIS-DAP Mode by pressing the `MODE SELECT` button. `KITPROG3 STATUS` LED is ON confirms board is in - proper mode. + proper mode. (Modustoolbox Software needs to be installed) - On the command line: $ cd ~/connectedhomeip + $ export CY_TOOLS_PATHS=/tools_3.2 $ python3 out/infineon-psoc6-lock/chip-psoc6-lock-example.flash.py ## Commissioning and cluster control @@ -116,12 +118,12 @@ commands. These power cycle the BlueTooth hardware and disable BR/EDR mode. ### Cluster control -- After successful commissioning, use the OnOff cluster command to toggle - device between On or Off states. +- After successful commissioning, use the doorlock cluster command to toggle + device between lock or Unlock states. - `$ ./out/debug/chip-tool onoff on 1234 1` + `$ ./out/debug/chip-tool doorlock lock-door 1234 1 --timedInteractionTimeoutMs 100` - `$ ./out/debug/chip-tool onoff off 1234 1` + `$ ./out/debug/chip-tool doorlock unlock-door 1234 1 --timedInteractionTimeoutMs 100` - Cluster OnOff can also be done using the `USER_BTN1` button on the board. This button is configured with `APP_LOCK_BUTTON` in `include/AppConfig.h`. diff --git a/integrations/docker/images/base/chip-build/version b/integrations/docker/images/base/chip-build/version index c797fa2a19186b..885f3e39127977 100644 --- a/integrations/docker/images/base/chip-build/version +++ b/integrations/docker/images/base/chip-build/version @@ -1 +1 @@ -68 : [Bouffalo Lab] Update gcc toolchain and flash tool +69 : [Infineon] Update ModusToolbox version to 3.2 diff --git a/integrations/docker/images/stage-2/chip-build-infineon/Dockerfile b/integrations/docker/images/stage-2/chip-build-infineon/Dockerfile index 5578b27ce50988..a6470044ff3080 100644 --- a/integrations/docker/images/stage-2/chip-build-infineon/Dockerfile +++ b/integrations/docker/images/stage-2/chip-build-infineon/Dockerfile @@ -13,25 +13,27 @@ RUN set -x \ file \ libglib2.0-0 \ libusb-1.0-0 sudo \ + libxcb-xinerama0 \ + libxcb-icccm4 \ + libxcb-image0 \ + libxcb-keysyms1 \ + libxcb-render-util0 \ + libxkbcommon-x11-0 \ && rm -rf /var/lib/apt/lists/ \ && : # last line # ------------------------------------------------------------------------------ -# Download and extract ModusToolbox 2.3 -RUN curl --fail --location --show-error \ - https://itoolspriv.infineon.com/itbhs/api/packages/com.ifx.tb.tool.modustoolbox/Versions/2.4.0.5972-public/artifacts/ModusToolbox_2.4.0.5972-linux-install.tar.gz/download?noredirect \ - -o /tmp/ModusToolbox_2.4.0.5972-linux-install.tar.gz \ - && tar -C /opt -zxf /tmp/ModusToolbox_2.4.0.5972-linux-install.tar.gz \ - && rm /tmp/ModusToolbox_2.4.0.5972-linux-install.tar.gz +# Download ModusToolbox 3.2 +RUN curl --fail --location --silent --show-error https://itoolspriv.infineon.com/itbhs/api/packages/com.ifx.tb.tool.modustoolbox/Versions/3.2.0.16028-public/artifacts/ModusToolbox_3.2.0.16028-linux-install.deb/download?noredirect -o /tmp/ModusToolbox_3.2.0.16028-linux-install.deb # ------------------------------------------------------------------------------ -# Execute post-build scripts -RUN /opt/ModusToolbox/tools_2.4/modus-shell/postinstall +# Install ModusToolbox 3.2 +RUN apt install /tmp/ModusToolbox_3.2.0.16028-linux-install.deb -# NOTE: udev rules are NOT installed: -# /opt/ModusToolbox/tools_2.4/fw-loader/udev_rules/install_rules.sh -# because docker containers do not support udev +# ------------------------------------------------------------------------------ +# Remove ModusToolbox deb file +RUN rm /tmp/ModusToolbox_3.2.0.16028-linux-install.deb # ------------------------------------------------------------------------------ -# Set environment variable required by ModusToolbox application makefiles -ENV CY_TOOLS_PATHS="/opt/ModusToolbox/tools_2.4" +# Run below command to Initialize the CY_TOOLS_PATHS environment variable defined in the /etc/profile.d/modustoolbox_3.2.sh file +RUN bash --login diff --git a/integrations/docker/images/vscode/chip-build-vscode/Dockerfile b/integrations/docker/images/vscode/chip-build-vscode/Dockerfile index 6bde4b8cb8431f..4dda050b9c496a 100644 --- a/integrations/docker/images/vscode/chip-build-vscode/Dockerfile +++ b/integrations/docker/images/vscode/chip-build-vscode/Dockerfile @@ -5,7 +5,7 @@ FROM ghcr.io/project-chip/chip-build-efr32:${VERSION} AS efr32 FROM ghcr.io/project-chip/chip-build-android:${VERSION} AS android FROM ghcr.io/project-chip/chip-build-esp32-qemu:${VERSION} as esp32 FROM ghcr.io/project-chip/chip-build-telink:${VERSION} AS telink -FROM ghcr.io/project-chip/chip-build-infineon:${VERSION} AS p6 +FROM ghcr.io/project-chip/chip-build-infineon:${VERSION} AS psoc6 FROM ghcr.io/project-chip/chip-build-tizen:${VERSION} AS tizen FROM ghcr.io/project-chip/chip-build-crosscompile:${VERSION} AS crosscompile FROM ghcr.io/project-chip/chip-build-ameba:${VERSION} AS ameba @@ -36,7 +36,7 @@ COPY --from=android /opt/android/sdk /opt/android/sdk COPY --from=android /opt/android/android-ndk-r23c /opt/android/android-ndk-r23c COPY --from=android /usr/lib/kotlinc /usr/lib/kotlinc -COPY --from=p6 /opt/ModusToolbox /opt/ModusToolbox +COPY --from=psoc6 /opt/Tools/ModusToolbox /opt/Tools/ModusToolbox COPY --from=telink /opt/telink/zephyrproject /opt/telink/zephyrproject COPY --from=telink /opt/telink/zephyr-sdk-0.16.1 /opt/telink/zephyr-sdk-0.16.1 @@ -111,7 +111,7 @@ ENV PATH $PATH:/usr/lib/kotlinc/bin ENV AMEBA_PATH=/opt/ameba/ambd_sdk_with_chip_non_NDA ENV ANDROID_HOME=/opt/android/sdk ENV ANDROID_NDK_HOME=/opt/android/android-ndk-r23c -ENV CY_TOOLS_PATHS="/opt/ModusToolbox/tools_2.4" +ENV CY_TOOLS_PATHS="/opt/Tools/ModusToolbox/tools_3.2" ENV SILABS_BOARD=BRD4186C # Keep GSDK_ROOT name until rename transition to SISDK is completed ENV GSDK_ROOT=/opt/silabs/simplicity_sdk/ diff --git a/scripts/examples/gn_psoc6_example.sh b/scripts/examples/gn_psoc6_example.sh index e3ae875b8e27a4..6cf6e054973656 100755 --- a/scripts/examples/gn_psoc6_example.sh +++ b/scripts/examples/gn_psoc6_example.sh @@ -16,26 +16,17 @@ # limitations under the License. # +# Install required software +if [[ -z "${CY_TOOLS_PATHS}" ]]; then + echo "*****************************************************************************************************" + echo "Install ModusToolbox Software v3.2 from https://www.infineon.com/modustoolbox and set CY_TOOLS_PATHS" + echo "*****************************************************************************************************" +fi + set -e # Build script for GN PSOC6 examples GitHub workflow. source "$(dirname "$0")/../../scripts/activate.sh" -# Install required software -if [ -d "/opt/ModusToolbox" ]; then - export CY_TOOLS_PATHS="/opt/ModusToolbox/tools_2.4" -elif [ -d "$HOME/ModusToolbox" ]; then - # Set CY TOOLS PATH - export CY_TOOLS_PATHS="$HOME/ModusToolbox/tools_2.4" -else - # Install Modustoolbox - curl --fail --location --silent --show-error https://itoolspriv.infineon.com/itbhs/api/packages/com.ifx.tb.tool.modustoolbox/Versions/2.4.0.5972-public/artifacts/ModusToolbox_2.4.0.5972-linux-install.tar.gz/download?noredirect -o /tmp/ModusToolbox_2.4.0.5972-linux-install.tar.gz && - tar -C "$HOME" -zxf /tmp/ModusToolbox_2.4.0.5972-linux-install.tar.gz && - rm /tmp/ModusToolbox_2.4.0.5972-linux-install.tar.gz - - # Set CY TOOLS PATH - export CY_TOOLS_PATHS="$HOME/ModusToolbox/tools_2.4" -fi - set -x env From 9efb5991178bb749a7d59f3ac76081f52cb3cfa0 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Wed, 7 Aug 2024 23:39:54 +0530 Subject: [PATCH 40/41] [ESP32] Fix compiling temperature measurement app when built with BT disabled (#34808) --- .../temperature-measurement-app/esp32/main/DeviceCallbacks.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/temperature-measurement-app/esp32/main/DeviceCallbacks.cpp b/examples/temperature-measurement-app/esp32/main/DeviceCallbacks.cpp index e0d7decc849616..88fee24b7535b6 100644 --- a/examples/temperature-measurement-app/esp32/main/DeviceCallbacks.cpp +++ b/examples/temperature-measurement-app/esp32/main/DeviceCallbacks.cpp @@ -23,6 +23,7 @@ * **/ #include "DeviceCallbacks.h" +#include static const char TAG[] = "echo-devicecallbacks"; From e0a765b31f12fc9fbf54684e72543219b721f211 Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Thu, 8 Aug 2024 06:15:26 +1200 Subject: [PATCH 41/41] Add chip_logging_backend option and 'none' and 'syslog' backends (#34830) * Tidy up stdio logging target dependencies Also rename from Logging.cpp to Stdio.cpp and add license header. * Add chip_logging_backend option and 'none' backend chip_logging_backend controls which backend is pulled in by the src/platform/logging:default target. The default is 'platform', retaining the current behavior. On Darwin, remove the no-op LoggingImpl and make stdio the default backend when compiling tools or example apps. Use the new 'none' backend when building Matter.framework, retaining current behavior. Depend on logging:default instead of logging:stdio for linux:app-main examples. * Add a syslog logging backend * Fix STM32 build * Use stdio logging backend for cirque tests The stdio and linux backends use slightly different output formats and the cirque tests currently only parse the stdio format correctly. * Apply suggestions from code review Co-authored-by: Boris Zbarsky * Fix stray space in GN string comparison --------- Co-authored-by: Boris Zbarsky --- examples/platform/linux/BUILD.gn | 2 +- scripts/build/gn_gen_cirque.sh | 2 +- .../Framework/chip_xcode_build_connector.sh | 1 + src/lib/core/core.gni | 25 +++++++ src/platform/Darwin/BUILD.gn | 1 - src/platform/logging/BUILD.gn | 39 ++++++++--- .../LoggingImpl.cpp => logging/impl/None.cpp} | 11 ++-- .../impl/{stdio/Logging.cpp => Stdio.cpp} | 17 ++++- src/platform/logging/impl/Syslog.cpp | 65 +++++++++++++++++++ src/platform/stm32/BUILD.gn | 3 +- src/system/SystemConfig.h | 4 +- 11 files changed, 148 insertions(+), 22 deletions(-) rename src/platform/{Darwin/LoggingImpl.cpp => logging/impl/None.cpp} (63%) rename src/platform/logging/impl/{stdio/Logging.cpp => Stdio.cpp} (73%) create mode 100644 src/platform/logging/impl/Syslog.cpp diff --git a/examples/platform/linux/BUILD.gn b/examples/platform/linux/BUILD.gn index 410b1a189245d2..1fcee183f131b3 100644 --- a/examples/platform/linux/BUILD.gn +++ b/examples/platform/linux/BUILD.gn @@ -93,7 +93,7 @@ source_set("app-main") { "${chip_root}/src/controller:controller", "${chip_root}/src/controller:gen_check_chip_controller_headers", "${chip_root}/src/lib", - "${chip_root}/src/platform/logging:stdio", + "${chip_root}/src/platform/logging:default", ] deps = [ ":ota-test-event-trigger", diff --git a/scripts/build/gn_gen_cirque.sh b/scripts/build/gn_gen_cirque.sh index d6f6bd86905a0e..1d89d802e7ad44 100755 --- a/scripts/build/gn_gen_cirque.sh +++ b/scripts/build/gn_gen_cirque.sh @@ -36,7 +36,7 @@ echo "Setup build environment" source "./scripts/activate.sh" echo "Build: GN configure" -gn --root="$CHIP_ROOT" gen --check --fail-on-unused-args out/debug --args='target_os="all"'"chip_build_tests=false chip_enable_wifi=false chip_im_force_fabric_quota_check=true enable_default_builds=false enable_host_gcc_build=true enable_standalone_chip_tool_build=true enable_linux_all_clusters_app_build=true enable_linux_lighting_app_build=true enable_linux_lit_icd_app_build=true" +gn --root="$CHIP_ROOT" gen --check --fail-on-unused-args out/debug --args='target_os="all" chip_logging_backend="stdio" chip_build_tests=false chip_enable_wifi=false chip_im_force_fabric_quota_check=true enable_default_builds=false enable_host_gcc_build=true enable_standalone_chip_tool_build=true enable_linux_all_clusters_app_build=true enable_linux_lighting_app_build=true enable_linux_lit_icd_app_build=true' echo "Build: Ninja build" time ninja -C out/debug all check diff --git a/src/darwin/Framework/chip_xcode_build_connector.sh b/src/darwin/Framework/chip_xcode_build_connector.sh index 33d4a441bf2019..b4a8195b8e0c52 100755 --- a/src/darwin/Framework/chip_xcode_build_connector.sh +++ b/src/darwin/Framework/chip_xcode_build_connector.sh @@ -103,6 +103,7 @@ declare -a args=( 'chip_enable_python_modules=false' 'chip_device_config_enable_dynamic_mrp_config=true' 'chip_log_message_max_size=4096' # might as well allow nice long log messages + 'chip_logging_backend="none"' # os_log() is integrated via CHIP_SYSTEM_CONFIG_PLATFORM_LOG 'chip_disable_platform_kvs=true' 'enable_fuzz_test_targets=false' "target_cpu=\"$target_cpu\"" diff --git a/src/lib/core/core.gni b/src/lib/core/core.gni index ba1d91fd28ca42..f2189198e36131 100644 --- a/src/lib/core/core.gni +++ b/src/lib/core/core.gni @@ -54,7 +54,23 @@ declare_args() { # Configure chip logging to output through external logging implementation. # External code will need to provide implementation for CHIP log output # function (LogV), which is defined in "src/platform/logging/LogV.h". + # Same as setting chip_logging_backend = "external" chip_use_external_logging = false +} + +declare_args() { + # Logging backend to use for targets that don't link a specific log + # backend (e.g. command line utilites usually use 'stdio'). Options: + # 'platform' - The default log backend of the device platform + # 'external' - External LogV implementation (src/platform/logging/LogV.h) + # 'none' - Discard all log output + # 'stdio' - Print to stdout + # 'syslog' - POSIX syslog() + if (chip_use_external_logging) { + chip_logging_backend = "external" + } else { + chip_logging_backend = "platform" + } # Enable short error strings. chip_config_short_error_str = false @@ -117,6 +133,15 @@ if (chip_target_style == "") { } } +assert( + chip_logging_backend == "platform" || chip_logging_backend == "external" || + chip_logging_backend == "none" || chip_logging_backend == "stdio" || + chip_logging_backend == "syslog", + "Please select a valid logging backend: platform, external, none, stdio, syslog") +assert( + !chip_use_external_logging || chip_logging_backend == "external", + "Setting chip_use_external_logging = true conflicts with selected chip_logging_backend") + assert(chip_target_style == "unix" || chip_target_style == "embedded", "Please select a valid target style: unix, embedded") diff --git a/src/platform/Darwin/BUILD.gn b/src/platform/Darwin/BUILD.gn index df4c0774e91627..0a56ce1eac4364 100644 --- a/src/platform/Darwin/BUILD.gn +++ b/src/platform/Darwin/BUILD.gn @@ -151,7 +151,6 @@ static_library("logging") { sources = [ "Logging.h", "Logging.mm", - "LoggingImpl.cpp", ] deps = [ diff --git a/src/platform/logging/BUILD.gn b/src/platform/logging/BUILD.gn index 9b26f40569f428..eb3c62154ce436 100644 --- a/src/platform/logging/BUILD.gn +++ b/src/platform/logging/BUILD.gn @@ -8,8 +8,8 @@ import("${chip_root}/src/lib/core/core.gni") import("${chip_root}/src/lib/shell/shell_device.gni") import("${chip_root}/src/platform/device.gni") -source_set("default") { - if (!chip_use_external_logging) { +group("default") { + if (chip_logging_backend == "platform") { deps = [] if (chip_use_pw_logging) { @@ -63,7 +63,7 @@ source_set("default") { } else if (chip_device_platform == "qpg") { deps += [ "${chip_root}/src/platform/qpg:logging" ] } else if (chip_device_platform == "darwin") { - deps += [ "${chip_root}/src/platform/Darwin:logging" ] + deps += [ ":stdio" ] # For tools / examples. The framework uses "none". } else if (chip_device_platform == "mw320") { deps += [ "${chip_root}/src/platform/nxp/mw320:logging" ] } else if (chip_device_platform == "k32w0" || @@ -82,22 +82,43 @@ source_set("default") { assert(chip_device_platform == "fake" || chip_device_platform == "external" || chip_device_platform == "none") } + } else if (chip_logging_backend == "none" || + chip_logging_backend == "stdio" || + chip_logging_backend == "syslog") { + deps = [ ":${chip_logging_backend}" ] + } else { + assert(chip_logging_backend == "external") } } source_set("headers") { public = [ "LogV.h" ] + public_deps = [ + "${chip_root}/src/lib/support:attributes", + "${chip_root}/src/lib/support:logging_constants", + ] +} + +source_set("none") { + sources = [ "impl/None.cpp" ] + deps = [ + ":headers", + "${chip_root}/src/platform:platform_base", + ] } source_set("stdio") { - sources = [ "impl/stdio/Logging.cpp" ] + sources = [ "impl/Stdio.cpp" ] + deps = [ + ":headers", + "${chip_root}/src/platform:platform_base", + ] +} +source_set("syslog") { + sources = [ "impl/Syslog.cpp" ] deps = [ ":headers", - "${chip_root}/src/lib/core:chip_config_header", - "${chip_root}/src/lib/support:attributes", - "${chip_root}/src/lib/support:logging_constants", - "${chip_root}/src/platform:platform_config_header", - "${chip_root}/src/platform/logging:headers", + "${chip_root}/src/platform:platform_base", ] } diff --git a/src/platform/Darwin/LoggingImpl.cpp b/src/platform/logging/impl/None.cpp similarity index 63% rename from src/platform/Darwin/LoggingImpl.cpp rename to src/platform/logging/impl/None.cpp index 2d6c1b3b744294..10f1b4dc87f54a 100644 --- a/src/platform/Darwin/LoggingImpl.cpp +++ b/src/platform/logging/impl/None.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2024 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. @@ -21,12 +21,11 @@ namespace chip { namespace Logging { namespace Platform { -void LogV(const char * module, uint8_t category, const char * msg, va_list v) +void LogV(const char *, uint8_t, const char *, va_list) { - // ChipPlatformLog expands to an os_log call directly (see Logging.h), so - // we don't need to do anything further here. However his function and the - // call to it still exist because of scenarios where a different logging - // backend (usually stdio) is swapped in at link time, e.g. for unit tests. + // This backend discards all log messages. This is useful when all log output + // is routed via `SetLogRedirectCallback()` and/or platform logging + // integration at the log macro level (`CHIP_SYSTEM_CONFIG_PLATFORM_LOG`). } } // namespace Platform diff --git a/src/platform/logging/impl/stdio/Logging.cpp b/src/platform/logging/impl/Stdio.cpp similarity index 73% rename from src/platform/logging/impl/stdio/Logging.cpp rename to src/platform/logging/impl/Stdio.cpp index d36fe2aae2dc64..47338de500b29d 100644 --- a/src/platform/logging/impl/stdio/Logging.cpp +++ b/src/platform/logging/impl/Stdio.cpp @@ -1,4 +1,19 @@ -/* See Project CHIP LICENSE file for licensing information. */ +/* + * + * Copyright (c) 2021-2024 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. + */ #include diff --git a/src/platform/logging/impl/Syslog.cpp b/src/platform/logging/impl/Syslog.cpp new file mode 100644 index 00000000000000..163e6d7398aefe --- /dev/null +++ b/src/platform/logging/impl/Syslog.cpp @@ -0,0 +1,65 @@ +/* + * + * Copyright (c) 2024 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. + */ + +#include + +#include +#include + +#include +#include + +namespace chip { +namespace Logging { +namespace Platform { + +namespace { +int LogPriority(uint8_t category) +{ + switch (category) + { + case kLogCategory_Error: + return LOG_ERR; + case kLogCategory_Progress: + return LOG_NOTICE; + default: + return LOG_DEBUG; + } +} +} // namespace + +void LogV(const char * module, uint8_t category, const char * msg, va_list v) +{ + static std::mutex sMutex; + static bool sInitialized = false; + static char sBuffer[CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE]; + std::lock_guard guard(sMutex); + + if (!sInitialized) + { + openlog(nullptr, 0, LOG_DAEMON); + sInitialized = true; + } + + // Pre-format the message so we can include the module name + vsnprintf(sBuffer, sizeof(sBuffer), msg, v); + syslog(LogPriority(category), "%s: %s", module, sBuffer); +} + +} // namespace Platform +} // namespace Logging +} // namespace chip diff --git a/src/platform/stm32/BUILD.gn b/src/platform/stm32/BUILD.gn index 9b2ed9008c858a..061a2c4c268465 100644 --- a/src/platform/stm32/BUILD.gn +++ b/src/platform/stm32/BUILD.gn @@ -39,7 +39,6 @@ static_library("stm32") { sources = [ "../FreeRTOS/SystemTimeSupport.cpp", "../SingletonConfigurationManager.cpp", - "../logging/impl/stdio/Logging.cpp", "BLEManagerImpl.cpp", "BLEManagerImpl.h", "BlePlatformConfig.h", @@ -69,7 +68,7 @@ static_library("stm32") { "SystemPlatformConfig.h", ] - deps += [ "${chip_root}/src/platform/logging:headers" ] + deps += [ "${chip_root}/src/platform/logging:stdio" ] } public = [ diff --git a/src/system/SystemConfig.h b/src/system/SystemConfig.h index b37cfe555278dd..58339df4be1e47 100644 --- a/src/system/SystemConfig.h +++ b/src/system/SystemConfig.h @@ -558,7 +558,9 @@ struct LwIPEvent; * @def CHIP_SYSTEM_CONFIG_PLATFORM_LOG * * @brief - * Defines whether (1) or not (0) the system uses a platform-specific logging implementation. + * Defines whether (1) or not (0) the system uses a platform-specific implementation of + * ChipLog* macros. Most platforms do not use this option and simply provide a logging + * backend that implements LogV. * * See CHIPLogging.h for details. */