From 353727739a4aa9b9733bc5eb6b8b5310c1e77581 Mon Sep 17 00:00:00 2001 From: "tennessee.carmelveilleux@gmail.com" Date: Thu, 14 Dec 2023 16:29:35 -0500 Subject: [PATCH 01/11] Implement TimeSnapshot command properly --- .../general-diagnostics-server.cpp | 40 +++++++++++++++++-- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp b/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp index 108cc0b7d7357f..cc609336e5914f 100644 --- a/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp +++ b/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp @@ -16,6 +16,11 @@ */ #include "general-diagnostics-server.h" + +#ifdef ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER +#include "app/clusters/time-synchronization-server/time-synchronization-server.h" +#endif // ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER + #include "app/server/Server.h" #include #include @@ -192,7 +197,8 @@ CHIP_ERROR GeneralDiagosticsAttrAccess::Read(const ConcreteReadAttributePath & a return ReadIfSupported(&DiagnosticDataProvider::GetRebootCount, aEncoder); } case UpTime::Id: { - return ReadIfSupported(&DiagnosticDataProvider::GetUpTime, aEncoder); + System::Clock::Seconds64 system_time_seconds = std::chrono::duration_cast(Server::GetInstance().TimeSinceInit()); + return aEncoder.Encode(static_cast(system_time_seconds.count())); } case TotalOperationalHours::Id: { return ReadIfSupported(&DiagnosticDataProvider::GetTotalOperationalHours, aEncoder); @@ -385,9 +391,35 @@ bool emberAfGeneralDiagnosticsClusterTestEventTriggerCallback(CommandHandler * c bool emberAfGeneralDiagnosticsClusterTimeSnapshotCallback(CommandHandler * commandObj, ConcreteCommandPath const & commandPath, Commands::TimeSnapshot::DecodableType const & commandData) { - // TODO(#30096): Command needs to be implemented. - ChipLogError(Zcl, "TimeSnapshot not yet supported!"); - commandObj->AddStatus(commandPath, Status::InvalidCommand); + ChipLogError(Zcl, "Received TimeSnapshot command!"); + + Commands::TimeSnapshotResponse::Type response; + + System::Clock::Microseconds64 posix_time_us{0}; + +#ifdef ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER + bool time_is_synced = false; + using Clusters::TimeSynchronization::GranularityEnum; + GranularityEnum granularity = Clusters::TimeSynchronization::TimeSynchronizationServer::Instance().GetGranularity(); + time_is_synced = (granularity == GranularityEnum::kSecondsGranularity) || (granularity == GranularityEnum::kMillisecondsGranularity) || (granularity == GranularityEnum::kMicrosecondsGranularity); + + if (time_is_synced) + { + CHIP_ERROR posix_time_err = System::SystemClock().GetClock_RealTime(posix_time_us); + if (posix_time_err != CHIP_NO_ERROR) { + ChipLogError(Zcl, "Failed to get POSIX real time: %" CHIP_ERROR_FORMAT, posix_time_err.Format()); + posix_time_us = System::Clock::Microseconds64{0}; + } + } +#endif // TIME_SYNCHRONIZATION_CLUSTER + System::Clock::Milliseconds64 system_time_ms = std::chrono::duration_cast(Server::GetInstance().TimeSinceInit()); + + response.systemTimeMs = static_cast(system_time_ms.count()); + if (posix_time_us.count() != 0) + { + response.posixTimeMs.SetNonNull(static_cast(std::chrono::duration_cast(posix_time_us).count())); + } + commandObj->AddResponse(commandPath, response); return true; } From 716cd9181c5fb610a5a0532980bf582c0aee3abd Mon Sep 17 00:00:00 2001 From: Tennessee Carmel-Veilleux Date: Fri, 22 Dec 2023 11:17:46 -0500 Subject: [PATCH 02/11] Add TC-DGGEN-2.4 --- .github/workflows/tests.yaml | 3 +- src/python_testing/TC_DGGEN_2_4.py | 193 +++++++++++++++++++ src/python_testing/TC_TIMESYNC_2_2.py | 3 +- src/python_testing/matter_testing_support.py | 25 ++- 4 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 src/python_testing/TC_DGGEN_2_4.py diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index a9c04f6d8f5a6b..af69363907f562 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -28,7 +28,7 @@ concurrency: env: CHIP_NO_LOG_TIMESTAMPS: true - + jobs: test_suites_linux: name: Test Suites - Linux @@ -477,6 +477,7 @@ jobs: scripts/run_in_python_env.sh out/venv './scripts/tests/run_python_test.py --script "src/python_testing/TC_TIMESYNC_2_12.py" --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --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: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/TC_TIMESYNC_2_13.py" --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --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: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/TC_TIMESYNC_3_1.py" --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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/TC_DGGEN_2_4.py" --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --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 --app out/linux-x64-lit-icd-ipv6only-no-ble-no-wifi-tsan-clang-test/lit-icd-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_ICDM_2_1.py" --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: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 --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_DA_1_5.py" --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: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 --app out/linux-x64-all-clusters-ipv6only-no-ble-no-wifi-tsan-clang-test/chip-all-clusters-app --factoryreset --app-args "--discriminator 1234 --KVS kvs1 --trace-to json:out/trace_data/app-{SCRIPT_BASE_NAME}.json" --script "src/python_testing/TC_IDM_1_2.py" --script-args "--storage-path admin_storage.json --commissioning-method on-network --discriminator 1234 --passcode 20202021 --trace-to json:out/trace_data/test-{SCRIPT_BASE_NAME}.json --trace-to perfetto:out/trace_data/test-{SCRIPT_BASE_NAME}.perfetto"' diff --git a/src/python_testing/TC_DGGEN_2_4.py b/src/python_testing/TC_DGGEN_2_4.py new file mode 100644 index 00000000000000..ea1e7a8154df4d --- /dev/null +++ b/src/python_testing/TC_DGGEN_2_4.py @@ -0,0 +1,193 @@ +# +# 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. +# + +import asyncio +import logging +import time + +import chip.clusters as Clusters +from chip.clusters.Types import NullValue +from chip.interaction_model import InteractionModelError, Status +from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main +from matter_testing_support import matter_epoch_us_from_utc_datetime, utc_datetime_from_matter_epoch_us, utc_datetime_from_posix_time_ms +from mobly import asserts + +logger = logging.getLogger(__name__) + + +class TC_DGGEN_2_4(MatterBaseTest): + async def read_diags_attribute_expect_success(self, attribute): + cluster = Clusters.Objects.GeneralDiagnostics + return await self.read_single_attribute_check_success(endpoint=0, cluster=cluster, attribute=attribute) + + async def read_timesync_attribute_expect_success(self, attribute): + cluster = Clusters.Objects.TimeSynchronization + return await self.read_single_attribute_check_success(endpoint=0, cluster=cluster, attribute=attribute) + + async def set_time_in_timesync(self, current_time: int): + endpoint = 0 + time_cluster = Clusters.Objects.TimeSynchronization + code = 0 + + try: + await self.send_single_cmd(cmd=time_cluster.Commands.SetUTCTime(UTCTime=current_time, granularity=time_cluster.Enums.GranularityEnum.kSecondsGranularity), endpoint=endpoint) + except InteractionModelError as e: + # The python layer discards the cluster specific portion of the status IB, so for now we just expect a generic FAILURE error + # see #26521 + code = e.status + + asserts.assert_true(code in [0, 1], "Unexpected error while trying to set the UTCTime") + + async def send_time_snapshot_expect_success(self): + endpoint = 0 + diags_cluster = Clusters.Objects.GeneralDiagnostics + code = 0 + + try: + response = await self.send_single_cmd(cmd=diags_cluster.Commands.TimeSnapshot(), endpoint=endpoint) + except InteractionModelError as e: + code = e.status + + asserts.assert_equal(code, 0, "Expected success of TimeSnapshot.") + return response + + @async_test_body + async def test_TC_GEN_2_4(self): + self.print_step(1, "Detect Time Synchronization UTCTime attribute presence") + + root_descriptor = await self.default_controller.ReadAttribute(self.dut_node_id, [(0, Clusters.Descriptor)]) + root_server_list = root_descriptor[0][Clusters.Descriptor][Clusters.Descriptor.Attributes.ServerList] + has_timesync = (Clusters.TimeSynchronization.id in root_server_list) + + testvar_TimeSyncSupported = False + + if has_timesync: + ts_attributes = await self.read_single_attribute(self.default_controller, node_id=self.dut_node_id, endpoint=0, attribute=Clusters.TimeSynchronization.Attributes.AttributeList) + has_utc_time = (Clusters.TimeSynchronization.Attributes.UTCTime.attribute_id in ts_attributes) + + if has_utc_time: + testvar_TimeSyncSupported = True + + self.print_step(2, "Read UpTime attribute, save as UpTime1") + testvar_UpTime1 = await self.read_diags_attribute_expect_success(Clusters.GeneralDiagnostics.Attributes.UpTime) + asserts.assert_greater(testvar_UpTime1, 0, "UpTime1 must be > 0") + + # Step 3 (Time Sync supported) + if testvar_TimeSyncSupported: + self.print_step(3, "Functional verifications when Time Synchronization is supported") + + self.print_step("3a", "Write current time to DUT") + # Get current time in the correct format to set via command. + th_utc = matter_epoch_us_from_utc_datetime(desired_datetime=None) + + await self.set_time_in_timesync(th_utc) + + self.print_step("3b", "Read current time from DUT") + testvar_UTCTime1 = await self.read_timesync_attribute_expect_success(Clusters.TimeSynchronization.Attributes.UTCTime) + asserts.assert_true(testvar_UTCTime1 != NullValue, "UTCTime1 readback must not be null") + + self.print_step("3c", "Wait for 1 second") + await asyncio.sleep(1) + + self.print_step("3d", "Send a first TimeSnapshot command and verify") + response = await self.send_time_snapshot_expect_success() + logging.info(f"Step 3d: {response}") + + # Verify that the DUT sends a TimeSnapshotResponse with the following conditions met: + # - Value of PosixTimeMs field is not null. + # - Value of (SystemTimeMs field / 1000) is greater than or equal to UpTime1 + # - PosixTimeMs field converted to a UTC timestamp is greater than or equal to UTCTime1 converted to a UTC timestamp. + # + # On success of prior verifications: + # - Save the value of the SystemTimeMs field as SystemTimeMs1. + # - Save the value of the PosixTimeMs field as PosixTimeMs1. + asserts.assert_true(response.posixTimeMs != NullValue, "PosixTimeMs field of TimeSnapshotResponse must not be null") + asserts.assert_greater_equal(response.systemTimeMs // 1000, testvar_UpTime1, + "System time in milliseconds must be >= UpTime1") + + utc_from_posix = utc_datetime_from_posix_time_ms(posix_time_ms=response.posixTimeMs) + utc_from_utctime1 = utc_datetime_from_matter_epoch_us(testvar_UTCTime1) + + asserts.assert_greater_equal( + utc_from_posix, utc_from_utctime1, "PosixTimeMs field converted to a UTC timestamp must be >= than UTCTime1 converted to a UTC timestamp") + + testvar_SystemTimeMs1 = response.systemTimeMs + testvar_PosixTimeMs1 = response.posixTimeMs + + self.print_step("3e", "Wait for 1 second") + await asyncio.sleep(1) + + self.print_step("3f", "Send a second TimeSnapshot command and verify") + + response = await self.send_time_snapshot_expect_success() + logging.info(f"Step 3f: {response}") + + # Verify that the DUT sends a TimeSnapshotResponse with the following fields: + # - Value of PosixTimeMs field is not null and greater than PosixTimeMs1. + # - Value of SystemTimeMs field is greater than SystemTimeMs1. + + asserts.assert_true(response.posixTimeMs != NullValue, "PosixTimeMs field of TimeSnapshotResponse must not be null") + asserts.assert_greater(response.posixTimeMs, testvar_PosixTimeMs1, + "POSIX time in milliseconds must be > PosixTimeMs1") + asserts.assert_greater(response.systemTimeMs, testvar_SystemTimeMs1, + "System time in milliseconds must be > SystemTimeMs1") + + self.print_step(4, "Skipped: Functional verifications when Time Synchronization is NOT supported") + + # Step 4 (Time Sync not supported) + else: # if not testvar_TimeSyncSupported: + self.print_step(3, "Skipped: Functional verifications when Time Synchronization is supported") + + self.print_step(4, "Functional verifications when Time Synchronization is NOT supported") + + self.print_step("4a", "Send a first TimeSnapshot command and verify") + response = await self.send_time_snapshot_expect_success() + logging.info(f"Step 4a: {response}") + + # Verify that the DUT sends a TimeSnapshotResponse with the following fields: + # - Value of PosixTimeMs field is null. + # - Value of (SystemTimeMs field / 1000) is greater than UpTime1. + # + # On success of prior verifications, save the value of SystemTimeMs field as SystemTimeMs1. + + asserts.assert_true(response.posixTimeMs == NullValue, "PosixTimeMs field of TimeSnapshotResponse must be null") + asserts.assert_greater_equal(response.systemTimeMs // 1000, testvar_UpTime1, + "System time in milliseconds must be >= UpTime1") + + testvar_SystemTimeMs1 = response.systemTimeMs + + self.print_step("4b", "Wait for 1 second") + await asyncio.sleep(1) + + self.print_step("4c", "Send a second TimeSnapshot command and verify") + + response = await self.send_time_snapshot_expect_success() + logging.info(f"Step 4c: {response}") + + # Verify that the DUT sends a TimeSnapshotResponse with the following fields: + # - Value of PosixTimeMs field is null. + # - Value of SystemTimeMs field is greater than SystemTimeMs1. + # + # On success of prior verifications, save the value of SystemTimeMs field as SystemTimeMs1. + + asserts.assert_true(response.posixTimeMs == NullValue, "PosixTimeMs field of TimeSnapshotResponse must be null") + asserts.assert_greater(response.systemTimeMs, testvar_SystemTimeMs1, + "System time in milliseconds must be > SystemTimeMs1") + + +if __name__ == "__main__": + default_matter_test_main() diff --git a/src/python_testing/TC_TIMESYNC_2_2.py b/src/python_testing/TC_TIMESYNC_2_2.py index 7e63708f358a59..f364c4443b3390 100644 --- a/src/python_testing/TC_TIMESYNC_2_2.py +++ b/src/python_testing/TC_TIMESYNC_2_2.py @@ -43,9 +43,10 @@ async def test_TC_TIMESYNC_2_2(self): self.print_step(2, "Read UTCTime attribute") utc_dut_initial = await self.read_ts_attribute_expect_success(endpoint=endpoint, attribute=attributes.UTCTime) th_utc = utc_time_in_matter_epoch() + + code = 0 try: await self.send_single_cmd(cmd=time_cluster.Commands.SetUTCTime(UTCTime=th_utc, granularity=time_cluster.Enums.GranularityEnum.kMillisecondsGranularity), endpoint=endpoint) - code = 0 except InteractionModelError as e: # The python layer discards the cluster specific portion of the status IB, so for now we just expect a generic FAILURE error # see #26521 diff --git a/src/python_testing/matter_testing_support.py b/src/python_testing/matter_testing_support.py index e486fa0304ab58..74a05b8ecb6db8 100644 --- a/src/python_testing/matter_testing_support.py +++ b/src/python_testing/matter_testing_support.py @@ -183,8 +183,10 @@ def type_matches(received_value, desired_type): else: return isinstance(received_value, desired_type) +# TODO(#31177): Need to add unit tests for all time conversion methods. -def utc_time_in_matter_epoch(desired_datetime: datetime = None): + +def utc_time_in_matter_epoch(desired_datetime: Optional[datetime] = None): """ Returns the time in matter epoch in us. If desired_datetime is None, it will return the current time. @@ -199,19 +201,36 @@ def utc_time_in_matter_epoch(desired_datetime: datetime = None): return utc_th_us +matter_epoch_us_from_utc_datetime = utc_time_in_matter_epoch + + +def utc_datetime_from_matter_epoch_us(matter_epoch_us: int) -> datetime: + """Returns the given Matter epoch time as a usable Python datetime in UTC.""" + delta_from_epoch = timedelta(microseconds=matter_epoch_us) + matter_epoch = datetime(2000, 1, 1, 0, 0, 0, 0, timezone.utc) + + return matter_epoch + delta_from_epoch + + +def utc_datetime_from_posix_time_ms(posix_time_ms: int) -> datetime: + millis = posix_time_ms % 1000 + seconds = posix_time_ms // 1000 + return datetime.fromtimestamp(seconds, timezone.utc) + timedelta(milliseconds=millis) + + def compare_time(received: int, offset: timedelta = timedelta(), utc: int = None, tolerance: timedelta = timedelta(seconds=5)) -> None: if utc is None: utc = utc_time_in_matter_epoch() # total seconds includes fractional for microseconds - expected = utc + offset.total_seconds()*1000000 + expected = utc + offset.total_seconds() * 1000000 delta_us = abs(expected - received) delta = timedelta(microseconds=delta_us) asserts.assert_less_equal(delta, tolerance, "Received time is out of tolerance") def get_wait_seconds_from_set_time(set_time_matter_us: int, wait_seconds: int): - seconds_passed = math.floor((utc_time_in_matter_epoch() - set_time_matter_us)/1000000) + seconds_passed = (utc_time_in_matter_epoch() - set_time_matter_us) // 1000000 return wait_seconds - seconds_passed From 7a5ed6e5686e927e72987d892b83f9abb866d8eb Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Fri, 22 Dec 2023 16:22:55 +0000 Subject: [PATCH 03/11] Restyled by clang-format --- .../general-diagnostics-server.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp b/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp index cc609336e5914f..5351a8355d9c23 100644 --- a/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp +++ b/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp @@ -197,7 +197,8 @@ CHIP_ERROR GeneralDiagosticsAttrAccess::Read(const ConcreteReadAttributePath & a return ReadIfSupported(&DiagnosticDataProvider::GetRebootCount, aEncoder); } case UpTime::Id: { - System::Clock::Seconds64 system_time_seconds = std::chrono::duration_cast(Server::GetInstance().TimeSinceInit()); + System::Clock::Seconds64 system_time_seconds = + std::chrono::duration_cast(Server::GetInstance().TimeSinceInit()); return aEncoder.Encode(static_cast(system_time_seconds.count())); } case TotalOperationalHours::Id: { @@ -395,29 +396,33 @@ bool emberAfGeneralDiagnosticsClusterTimeSnapshotCallback(CommandHandler * comma Commands::TimeSnapshotResponse::Type response; - System::Clock::Microseconds64 posix_time_us{0}; + System::Clock::Microseconds64 posix_time_us{ 0 }; #ifdef ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER bool time_is_synced = false; using Clusters::TimeSynchronization::GranularityEnum; GranularityEnum granularity = Clusters::TimeSynchronization::TimeSynchronizationServer::Instance().GetGranularity(); - time_is_synced = (granularity == GranularityEnum::kSecondsGranularity) || (granularity == GranularityEnum::kMillisecondsGranularity) || (granularity == GranularityEnum::kMicrosecondsGranularity); + time_is_synced = (granularity == GranularityEnum::kSecondsGranularity) || + (granularity == GranularityEnum::kMillisecondsGranularity) || (granularity == GranularityEnum::kMicrosecondsGranularity); if (time_is_synced) { CHIP_ERROR posix_time_err = System::SystemClock().GetClock_RealTime(posix_time_us); - if (posix_time_err != CHIP_NO_ERROR) { + if (posix_time_err != CHIP_NO_ERROR) + { ChipLogError(Zcl, "Failed to get POSIX real time: %" CHIP_ERROR_FORMAT, posix_time_err.Format()); - posix_time_us = System::Clock::Microseconds64{0}; + posix_time_us = System::Clock::Microseconds64{ 0 }; } } #endif // TIME_SYNCHRONIZATION_CLUSTER - System::Clock::Milliseconds64 system_time_ms = std::chrono::duration_cast(Server::GetInstance().TimeSinceInit()); + System::Clock::Milliseconds64 system_time_ms = + std::chrono::duration_cast(Server::GetInstance().TimeSinceInit()); response.systemTimeMs = static_cast(system_time_ms.count()); if (posix_time_us.count() != 0) { - response.posixTimeMs.SetNonNull(static_cast(std::chrono::duration_cast(posix_time_us).count())); + response.posixTimeMs.SetNonNull( + static_cast(std::chrono::duration_cast(posix_time_us).count())); } commandObj->AddResponse(commandPath, response); return true; From 5f3e1882432267638eb1fd63cfb874f9ed1a96b6 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Fri, 22 Dec 2023 16:22:58 +0000 Subject: [PATCH 04/11] Restyled by isort --- src/python_testing/TC_DGGEN_2_4.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python_testing/TC_DGGEN_2_4.py b/src/python_testing/TC_DGGEN_2_4.py index ea1e7a8154df4d..7e71627f7f78e6 100644 --- a/src/python_testing/TC_DGGEN_2_4.py +++ b/src/python_testing/TC_DGGEN_2_4.py @@ -22,8 +22,8 @@ import chip.clusters as Clusters from chip.clusters.Types import NullValue from chip.interaction_model import InteractionModelError, Status -from matter_testing_support import MatterBaseTest, async_test_body, default_matter_test_main -from matter_testing_support import matter_epoch_us_from_utc_datetime, utc_datetime_from_matter_epoch_us, utc_datetime_from_posix_time_ms +from matter_testing_support import (MatterBaseTest, async_test_body, default_matter_test_main, matter_epoch_us_from_utc_datetime, + utc_datetime_from_matter_epoch_us, utc_datetime_from_posix_time_ms) from mobly import asserts logger = logging.getLogger(__name__) From 5ab306f9f2df776a49515c759f78ad1c0a80e918 Mon Sep 17 00:00:00 2001 From: Tennessee Carmel-Veilleux Date: Fri, 22 Dec 2023 15:27:23 -0500 Subject: [PATCH 05/11] Fix lint --- src/python_testing/TC_DGGEN_2_4.py | 1 - src/python_testing/matter_testing_support.py | 1 - 2 files changed, 2 deletions(-) diff --git a/src/python_testing/TC_DGGEN_2_4.py b/src/python_testing/TC_DGGEN_2_4.py index 7e71627f7f78e6..04f4c6ceea3122 100644 --- a/src/python_testing/TC_DGGEN_2_4.py +++ b/src/python_testing/TC_DGGEN_2_4.py @@ -17,7 +17,6 @@ import asyncio import logging -import time import chip.clusters as Clusters from chip.clusters.Types import NullValue diff --git a/src/python_testing/matter_testing_support.py b/src/python_testing/matter_testing_support.py index 74a05b8ecb6db8..8d55d18e148e2e 100644 --- a/src/python_testing/matter_testing_support.py +++ b/src/python_testing/matter_testing_support.py @@ -21,7 +21,6 @@ import inspect import json import logging -import math import os import pathlib import queue From 6a19e1e9b0aded4dbc117ffa3ebc34db0f62a590 Mon Sep 17 00:00:00 2001 From: Tennessee Carmel-Veilleux Date: Fri, 22 Dec 2023 15:27:42 -0500 Subject: [PATCH 06/11] Try to fix build --- src/app/chip_data_model.gni | 4 +++- .../general-diagnostics-server.cpp | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index b882c875dc3ac2..cda01f3224329a 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -273,7 +273,9 @@ template("chip_data_model") { "${_app_root}/clusters/${cluster}/TimeSyncDataProvider.cpp", ] defines += - [ "TIME_SYNC_ENABLE_TSC_FEATURE=${time_sync_enable_tsc_feature}" ] + [ "TIME_SYNC_ENABLE_TSC_FEATURE=${time_sync_enable_tsc_feature}", + "TIME_SYNCHRONIZATION_CLUSTER_INCLUDED=1" + ] } else if (cluster == "scenes-server") { sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp", diff --git a/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp b/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp index 5351a8355d9c23..8c352093995318 100644 --- a/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp +++ b/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp @@ -17,9 +17,9 @@ #include "general-diagnostics-server.h" -#ifdef ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER +#ifdef TIME_SYNCHRONIZATION_CLUSTER_INCLUDED #include "app/clusters/time-synchronization-server/time-synchronization-server.h" -#endif // ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER +#endif // TIME_SYNCHRONIZATION_CLUSTER_INCLUDED #include "app/server/Server.h" #include @@ -398,6 +398,7 @@ bool emberAfGeneralDiagnosticsClusterTimeSnapshotCallback(CommandHandler * comma System::Clock::Microseconds64 posix_time_us{ 0 }; +#ifdef TIME_SYNCHRONIZATION_CLUSTER_INCLUDED #ifdef ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER bool time_is_synced = false; using Clusters::TimeSynchronization::GranularityEnum; @@ -414,7 +415,9 @@ bool emberAfGeneralDiagnosticsClusterTimeSnapshotCallback(CommandHandler * comma posix_time_us = System::Clock::Microseconds64{ 0 }; } } -#endif // TIME_SYNCHRONIZATION_CLUSTER +#endif // ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER +#endif // TIME_SYNCHRONIZATION_CLUSTER_INCLUDED + System::Clock::Milliseconds64 system_time_ms = std::chrono::duration_cast(Server::GetInstance().TimeSinceInit()); From 914917e4cc7e9f9dc7d268ccdf3edb8ae5168615 Mon Sep 17 00:00:00 2001 From: Tennessee Carmel-Veilleux Date: Fri, 22 Dec 2023 15:40:49 -0500 Subject: [PATCH 07/11] Fix lint some more --- src/python_testing/TC_DGGEN_2_4.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python_testing/TC_DGGEN_2_4.py b/src/python_testing/TC_DGGEN_2_4.py index 04f4c6ceea3122..b2f599323b5f9f 100644 --- a/src/python_testing/TC_DGGEN_2_4.py +++ b/src/python_testing/TC_DGGEN_2_4.py @@ -20,7 +20,7 @@ import chip.clusters as Clusters from chip.clusters.Types import NullValue -from chip.interaction_model import InteractionModelError, Status +from chip.interaction_model import InteractionModelError from matter_testing_support import (MatterBaseTest, async_test_body, default_matter_test_main, matter_epoch_us_from_utc_datetime, utc_datetime_from_matter_epoch_us, utc_datetime_from_posix_time_ms) from mobly import asserts From d6e42b0b474829e2b0d2d70c6e550831ad43ade3 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Fri, 22 Dec 2023 20:42:22 +0000 Subject: [PATCH 08/11] Restyled by gn --- src/app/chip_data_model.gni | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index cda01f3224329a..b1609e4ada70b7 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -272,10 +272,10 @@ template("chip_data_model") { "${_app_root}/clusters/${cluster}/DefaultTimeSyncDelegate.cpp", "${_app_root}/clusters/${cluster}/TimeSyncDataProvider.cpp", ] - defines += - [ "TIME_SYNC_ENABLE_TSC_FEATURE=${time_sync_enable_tsc_feature}", - "TIME_SYNCHRONIZATION_CLUSTER_INCLUDED=1" - ] + defines += [ + "TIME_SYNC_ENABLE_TSC_FEATURE=${time_sync_enable_tsc_feature}", + "TIME_SYNCHRONIZATION_CLUSTER_INCLUDED=1", + ] } else if (cluster == "scenes-server") { sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp", From 630036afd8ee4f864fa240b7e941b57dff276ed5 Mon Sep 17 00:00:00 2001 From: Tennessee Carmel-Veilleux Date: Wed, 10 Jan 2024 14:46:04 -0500 Subject: [PATCH 09/11] Address review comments --- src/app/chip_data_model.gni | 5 +--- .../general-diagnostics-server.cpp | 28 ++++++++++++++----- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index b1609e4ada70b7..96a3d29849c871 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -272,10 +272,7 @@ template("chip_data_model") { "${_app_root}/clusters/${cluster}/DefaultTimeSyncDelegate.cpp", "${_app_root}/clusters/${cluster}/TimeSyncDataProvider.cpp", ] - defines += [ - "TIME_SYNC_ENABLE_TSC_FEATURE=${time_sync_enable_tsc_feature}", - "TIME_SYNCHRONIZATION_CLUSTER_INCLUDED=1", - ] + defines += [ "TIME_SYNC_ENABLE_TSC_FEATURE=${time_sync_enable_tsc_feature}" ] } else if (cluster == "scenes-server") { sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp", diff --git a/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp b/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp index 8c352093995318..261babd056b141 100644 --- a/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp +++ b/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp @@ -17,9 +17,11 @@ #include "general-diagnostics-server.h" -#ifdef TIME_SYNCHRONIZATION_CLUSTER_INCLUDED -#include "app/clusters/time-synchronization-server/time-synchronization-server.h" -#endif // TIME_SYNCHRONIZATION_CLUSTER_INCLUDED +#ifdef ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER +// Need the `nogncheck` because it's inter-cluster dependency and this +// breaks GN deps checks since that doesn't know how to deal with #ifdef'd includes :(. +#include "app/clusters/time-synchronization-server/time-synchronization-server.h" // nogncheck +#endif // ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER #include "app/server/Server.h" #include @@ -398,13 +400,26 @@ bool emberAfGeneralDiagnosticsClusterTimeSnapshotCallback(CommandHandler * comma System::Clock::Microseconds64 posix_time_us{ 0 }; -#ifdef TIME_SYNCHRONIZATION_CLUSTER_INCLUDED #ifdef ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER bool time_is_synced = false; using Clusters::TimeSynchronization::GranularityEnum; GranularityEnum granularity = Clusters::TimeSynchronization::TimeSynchronizationServer::Instance().GetGranularity(); - time_is_synced = (granularity == GranularityEnum::kSecondsGranularity) || - (granularity == GranularityEnum::kMillisecondsGranularity) || (granularity == GranularityEnum::kMicrosecondsGranularity); + switch (granularity) + { + case GranularityEnum::kUnknownEnumValue: + case GranularityEnum::kNoTimeGranularity: + time_is_synced = false; + break; + case GranularityEnum::kMinutesGranularity: + // Minute granularity is not deemed good enough for TimeSnapshot to report PosixTimeMs, by spec. + time_is_synced = false; + break; + case GranularityEnum::kSecondsGranularity: + case GranularityEnum::kMillisecondsGranularity: + case GranularityEnum::kMicrosecondsGranularity: + time_is_synced = true; + break; + } if (time_is_synced) { @@ -416,7 +431,6 @@ bool emberAfGeneralDiagnosticsClusterTimeSnapshotCallback(CommandHandler * comma } } #endif // ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER -#endif // TIME_SYNCHRONIZATION_CLUSTER_INCLUDED System::Clock::Milliseconds64 system_time_ms = std::chrono::duration_cast(Server::GetInstance().TimeSinceInit()); From 86258effea6173b93c28edc621d011d704804f1c Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 10 Jan 2024 19:48:06 +0000 Subject: [PATCH 10/11] Restyled by clang-format --- .../general-diagnostics-server.cpp | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp b/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp index 261babd056b141..ba71b049938f8c 100644 --- a/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp +++ b/src/app/clusters/general-diagnostics-server/general-diagnostics-server.cpp @@ -21,7 +21,7 @@ // Need the `nogncheck` because it's inter-cluster dependency and this // breaks GN deps checks since that doesn't know how to deal with #ifdef'd includes :(. #include "app/clusters/time-synchronization-server/time-synchronization-server.h" // nogncheck -#endif // ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER +#endif // ZCL_USING_TIME_SYNCHRONIZATION_CLUSTER_SERVER #include "app/server/Server.h" #include @@ -406,19 +406,19 @@ bool emberAfGeneralDiagnosticsClusterTimeSnapshotCallback(CommandHandler * comma GranularityEnum granularity = Clusters::TimeSynchronization::TimeSynchronizationServer::Instance().GetGranularity(); switch (granularity) { - case GranularityEnum::kUnknownEnumValue: - case GranularityEnum::kNoTimeGranularity: - time_is_synced = false; - break; - case GranularityEnum::kMinutesGranularity: - // Minute granularity is not deemed good enough for TimeSnapshot to report PosixTimeMs, by spec. - time_is_synced = false; - break; - case GranularityEnum::kSecondsGranularity: - case GranularityEnum::kMillisecondsGranularity: - case GranularityEnum::kMicrosecondsGranularity: - time_is_synced = true; - break; + case GranularityEnum::kUnknownEnumValue: + case GranularityEnum::kNoTimeGranularity: + time_is_synced = false; + break; + case GranularityEnum::kMinutesGranularity: + // Minute granularity is not deemed good enough for TimeSnapshot to report PosixTimeMs, by spec. + time_is_synced = false; + break; + case GranularityEnum::kSecondsGranularity: + case GranularityEnum::kMillisecondsGranularity: + case GranularityEnum::kMicrosecondsGranularity: + time_is_synced = true; + break; } if (time_is_synced) From e0fd92d81bdcc08ba4acdd57a788e937fa43b4c8 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 10 Jan 2024 19:48:12 +0000 Subject: [PATCH 11/11] Restyled by gn --- src/app/chip_data_model.gni | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index 96a3d29849c871..b882c875dc3ac2 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -272,7 +272,8 @@ template("chip_data_model") { "${_app_root}/clusters/${cluster}/DefaultTimeSyncDelegate.cpp", "${_app_root}/clusters/${cluster}/TimeSyncDataProvider.cpp", ] - defines += [ "TIME_SYNC_ENABLE_TSC_FEATURE=${time_sync_enable_tsc_feature}" ] + defines += + [ "TIME_SYNC_ENABLE_TSC_FEATURE=${time_sync_enable_tsc_feature}" ] } else if (cluster == "scenes-server") { sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp",