From 92e907b3f5ab00852b19064fa44b0b73ad6b6557 Mon Sep 17 00:00:00 2001 From: Pradip De Date: Wed, 22 Jan 2025 19:53:42 +0000 Subject: [PATCH 01/40] Use separate randomized port for each TCP test case. (#37144) Previously, all test cases in a single test run were using the same random port, and it caused some flakiness because sometimes the kernel could still be holding on to the previous test case port and, as a result, the next test case failed to bind throwing an "Address Already In Use" error. --- src/transport/raw/tests/TestTCP.cpp | 99 ++++++++++++++++------------- 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/src/transport/raw/tests/TestTCP.cpp b/src/transport/raw/tests/TestTCP.cpp index 130c99d9114752..213eb6c757eed6 100644 --- a/src/transport/raw/tests/TestTCP.cpp +++ b/src/transport/raw/tests/TestTCP.cpp @@ -53,7 +53,6 @@ namespace { constexpr size_t kMaxTcpActiveConnectionCount = 4; constexpr size_t kMaxTcpPendingPackets = 4; constexpr size_t kPacketSizeBytes = sizeof(uint32_t); -uint16_t gChipTCPPort = static_cast(CHIP_PORT + chip::Crypto::GetRandU16() % 100); chip::Transport::AppTCPConnectionCallbackCtxt gAppTCPConnCbCtxt; chip::Transport::ActiveTCPConnectionState * gActiveTCPConnState = nullptr; @@ -67,6 +66,11 @@ constexpr uint32_t kMessageCounter = 18; const char PAYLOAD[] = "Hello!"; const char messageSize_TEST[] = "\x00\x00\x00\x00"; +uint16_t GetRandomPort() +{ + return static_cast(CHIP_PORT + chip::Crypto::GetRandU16() % 100); +} + class MockTransportMgrDelegate : public chip::TransportMgrDelegate { public: @@ -135,11 +139,10 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate } } - void InitializeMessageTest(TCPImpl & tcp, const IPAddress & addr) + void InitializeMessageTest(TCPImpl & tcp, const IPAddress & addr, uint16_t port) { - CHIP_ERROR err = tcp.Init(Transport::TcpListenParameters(mIOContext->GetTCPEndPointManager()) - .SetAddressType(addr.Type()) - .SetListenPort(gChipTCPPort)); + CHIP_ERROR err = tcp.Init( + Transport::TcpListenParameters(mIOContext->GetTCPEndPointManager()).SetAddressType(addr.Type()).SetListenPort(port)); // retry a few times in case the port is somehow in use. // this is a WORKAROUND for flaky testing if we run tests very fast after each other. @@ -160,7 +163,7 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate chip::test_utils::SleepMillis(100); err = tcp.Init(Transport::TcpListenParameters(mIOContext->GetTCPEndPointManager()) .SetAddressType(addr.Type()) - .SetListenPort(gChipTCPPort)); + .SetListenPort(port)); } EXPECT_EQ(err, CHIP_NO_ERROR); @@ -178,7 +181,7 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate gAppTCPConnCbCtxt.connClosedCb = nullptr; } - void SingleMessageTest(TCPImpl & tcp, const IPAddress & addr) + void SingleMessageTest(TCPImpl & tcp, const IPAddress & addr, uint16_t port) { chip::System::PacketBufferHandle buffer = chip::System::PacketBufferHandle::NewWithData(PAYLOAD, sizeof(PAYLOAD)); ASSERT_FALSE(buffer.IsNull()); @@ -193,7 +196,7 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate EXPECT_EQ(err, CHIP_NO_ERROR); // Should be able to send a message to itself by just calling send. - err = tcp.SendMessage(Transport::PeerAddress::TCP(addr, gChipTCPPort), std::move(buffer)); + err = tcp.SendMessage(Transport::PeerAddress::TCP(addr, port), std::move(buffer)); EXPECT_EQ(err, CHIP_NO_ERROR); mIOContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [this]() { return mReceiveHandlerCallCount != 0; }); @@ -202,38 +205,38 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate SetCallback(nullptr); } - void ConnectTest(TCPImpl & tcp, const IPAddress & addr) + void ConnectTest(TCPImpl & tcp, const IPAddress & addr, uint16_t port) { // Connect and wait for seeing active connection - CHIP_ERROR err = tcp.TCPConnect(Transport::PeerAddress::TCP(addr, gChipTCPPort), &gAppTCPConnCbCtxt, &gActiveTCPConnState); + CHIP_ERROR err = tcp.TCPConnect(Transport::PeerAddress::TCP(addr, port), &gAppTCPConnCbCtxt, &gActiveTCPConnState); EXPECT_EQ(err, CHIP_NO_ERROR); mIOContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [&tcp]() { return tcp.HasActiveConnections(); }); EXPECT_EQ(tcp.HasActiveConnections(), true); } - void HandleConnectCompleteCbCalledTest(TCPImpl & tcp, const IPAddress & addr) + void HandleConnectCompleteCbCalledTest(TCPImpl & tcp, const IPAddress & addr, uint16_t port) { // Connect and wait for seeing active connection and connection complete // handler being called. - CHIP_ERROR err = tcp.TCPConnect(Transport::PeerAddress::TCP(addr, gChipTCPPort), &gAppTCPConnCbCtxt, &gActiveTCPConnState); + CHIP_ERROR err = tcp.TCPConnect(Transport::PeerAddress::TCP(addr, port), &gAppTCPConnCbCtxt, &gActiveTCPConnState); EXPECT_EQ(err, CHIP_NO_ERROR); mIOContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [this]() { return mHandleConnectionCompleteCalled; }); EXPECT_EQ(mHandleConnectionCompleteCalled, true); } - void HandleConnectCloseCbCalledTest(TCPImpl & tcp, const IPAddress & addr) + void HandleConnectCloseCbCalledTest(TCPImpl & tcp, const IPAddress & addr, uint16_t port) { // Connect and wait for seeing active connection and connection complete // handler being called. - CHIP_ERROR err = tcp.TCPConnect(Transport::PeerAddress::TCP(addr, gChipTCPPort), &gAppTCPConnCbCtxt, &gActiveTCPConnState); + CHIP_ERROR err = tcp.TCPConnect(Transport::PeerAddress::TCP(addr, port), &gAppTCPConnCbCtxt, &gActiveTCPConnState); EXPECT_EQ(err, CHIP_NO_ERROR); mIOContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [this]() { return mHandleConnectionCompleteCalled; }); EXPECT_EQ(mHandleConnectionCompleteCalled, true); - tcp.TCPDisconnect(Transport::PeerAddress::TCP(addr, gChipTCPPort)); + tcp.TCPDisconnect(Transport::PeerAddress::TCP(addr, port)); mIOContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [&tcp]() { return !tcp.HasActiveConnections(); }); EXPECT_EQ(mHandleConnectionCloseCalled, true); } @@ -246,10 +249,10 @@ class MockTransportMgrDelegate : public chip::TransportMgrDelegate EXPECT_EQ(tcp.HasActiveConnections(), false); } - void DisconnectTest(TCPImpl & tcp, const IPAddress & addr) + void DisconnectTest(TCPImpl & tcp, const IPAddress & addr, uint16_t port) { // Disconnect and wait for seeing peer close - tcp.TCPDisconnect(Transport::PeerAddress::TCP(addr, gChipTCPPort)); + tcp.TCPDisconnect(Transport::PeerAddress::TCP(addr, port)); mIOContext->DriveIOUntil(chip::System::Clock::Seconds16(5), [&tcp]() { return !tcp.HasActiveConnections(); }); EXPECT_EQ(tcp.HasActiveConnections(), false); } @@ -449,8 +452,9 @@ class TestTCP : public ::testing::Test { TCPImpl tcp; - CHIP_ERROR err = tcp.Init( - Transport::TcpListenParameters(mIOContext->GetTCPEndPointManager()).SetAddressType(type).SetListenPort(gChipTCPPort)); + uint16_t port = GetRandomPort(); + CHIP_ERROR err = + tcp.Init(Transport::TcpListenParameters(mIOContext->GetTCPEndPointManager()).SetAddressType(type).SetListenPort(port)); EXPECT_EQ(err, CHIP_NO_ERROR); } @@ -460,51 +464,56 @@ class TestTCP : public ::testing::Test { TCPImpl tcp; + uint16_t port = GetRandomPort(); MockTransportMgrDelegate gMockTransportMgrDelegate(mIOContext); - gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); - gMockTransportMgrDelegate.SingleMessageTest(tcp, addr); - gMockTransportMgrDelegate.DisconnectTest(tcp, addr); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr, port); + gMockTransportMgrDelegate.SingleMessageTest(tcp, addr, port); + gMockTransportMgrDelegate.DisconnectTest(tcp, addr, port); } void ConnectToSelfTest(const IPAddress & addr) { TCPImpl tcp; + uint16_t port = GetRandomPort(); MockTransportMgrDelegate gMockTransportMgrDelegate(mIOContext); - gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); - gMockTransportMgrDelegate.ConnectTest(tcp, addr); - gMockTransportMgrDelegate.DisconnectTest(tcp, addr); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr, port); + gMockTransportMgrDelegate.ConnectTest(tcp, addr, port); + gMockTransportMgrDelegate.DisconnectTest(tcp, addr, port); } void ConnectSendMessageThenCloseTest(const IPAddress & addr) { TCPImpl tcp; + uint16_t port = GetRandomPort(); MockTransportMgrDelegate gMockTransportMgrDelegate(mIOContext); - gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); - gMockTransportMgrDelegate.ConnectTest(tcp, addr); - gMockTransportMgrDelegate.SingleMessageTest(tcp, addr); - gMockTransportMgrDelegate.DisconnectTest(tcp, addr); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr, port); + gMockTransportMgrDelegate.ConnectTest(tcp, addr, port); + gMockTransportMgrDelegate.SingleMessageTest(tcp, addr, port); + gMockTransportMgrDelegate.DisconnectTest(tcp, addr, port); } void HandleConnCompleteTest(const IPAddress & addr) { TCPImpl tcp; + uint16_t port = GetRandomPort(); MockTransportMgrDelegate gMockTransportMgrDelegate(mIOContext); - gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); - gMockTransportMgrDelegate.HandleConnectCompleteCbCalledTest(tcp, addr); - gMockTransportMgrDelegate.DisconnectTest(tcp, addr); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr, port); + gMockTransportMgrDelegate.HandleConnectCompleteCbCalledTest(tcp, addr, port); + gMockTransportMgrDelegate.DisconnectTest(tcp, addr, port); } void HandleConnCloseTest(const IPAddress & addr) { TCPImpl tcp; + uint16_t port = GetRandomPort(); MockTransportMgrDelegate gMockTransportMgrDelegate(mIOContext); - gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); - gMockTransportMgrDelegate.HandleConnectCloseCbCalledTest(tcp, addr); - gMockTransportMgrDelegate.DisconnectTest(tcp, addr); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr, port); + gMockTransportMgrDelegate.HandleConnectCloseCbCalledTest(tcp, addr, port); + gMockTransportMgrDelegate.DisconnectTest(tcp, addr, port); } // Callback used by CheckProcessReceivedBuffer. @@ -556,8 +565,9 @@ TEST_F(TestTCP, InitializeAsTCPClient) { TCPImpl tcp; auto tcpListenParams = Transport::TcpListenParameters(mIOContext->GetTCPEndPointManager()); + uint16_t port = GetRandomPort(); CHIP_ERROR err = - tcp.Init(tcpListenParams.SetAddressType(IPAddressType::kIPv6).SetListenPort(gChipTCPPort).SetServerListenEnabled(false)); + tcp.Init(tcpListenParams.SetAddressType(IPAddressType::kIPv6).SetListenPort(port).SetServerListenEnabled(false)); EXPECT_EQ(err, CHIP_NO_ERROR); @@ -570,7 +580,8 @@ TEST_F(TestTCP, InitializeAsTCPClientServer) TCPImpl tcp; auto tcpListenParams = Transport::TcpListenParameters(mIOContext->GetTCPEndPointManager()); - CHIP_ERROR err = tcp.Init(tcpListenParams.SetAddressType(IPAddressType::kIPv6).SetListenPort(gChipTCPPort)); + uint16_t port = GetRandomPort(); + CHIP_ERROR err = tcp.Init(tcpListenParams.SetAddressType(IPAddressType::kIPv6).SetListenPort(port)); EXPECT_EQ(err, CHIP_NO_ERROR); @@ -643,11 +654,12 @@ TEST_F(TestTCP, CheckTCPEndpointAfterCloseTest) IPAddress addr; IPAddress::FromString("::1", addr); + uint16_t port = GetRandomPort(); MockTransportMgrDelegate gMockTransportMgrDelegate(mIOContext); - gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); - gMockTransportMgrDelegate.ConnectTest(tcp, addr); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr, port); + gMockTransportMgrDelegate.ConnectTest(tcp, addr, port); - Transport::PeerAddress lPeerAddress = Transport::PeerAddress::TCP(addr, gChipTCPPort); + Transport::PeerAddress lPeerAddress = Transport::PeerAddress::TCP(addr, port); void * state = TestAccess::FindActiveConnection(tcp, lPeerAddress); ASSERT_NE(state, nullptr); TCPEndPoint * lEndPoint = TestAccess::GetEndpoint(state); @@ -666,14 +678,15 @@ TEST_F(TestTCP, CheckProcessReceivedBuffer) IPAddress addr; IPAddress::FromString("::1", addr); + uint16_t port = GetRandomPort(); MockTransportMgrDelegate gMockTransportMgrDelegate(mIOContext); - gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr); + gMockTransportMgrDelegate.InitializeMessageTest(tcp, addr, port); // Send a packet to get TCP going, so that we can find a TCPEndPoint to pass to ProcessReceivedBuffer. // (The current TCPEndPoint implementation is not effectively mockable.) - gMockTransportMgrDelegate.SingleMessageTest(tcp, addr); + gMockTransportMgrDelegate.SingleMessageTest(tcp, addr, port); - Transport::PeerAddress lPeerAddress = Transport::PeerAddress::TCP(addr, gChipTCPPort); + Transport::PeerAddress lPeerAddress = Transport::PeerAddress::TCP(addr, port); void * state = TestAccess::FindActiveConnection(tcp, lPeerAddress); ASSERT_NE(state, nullptr); TCPEndPoint * lEndPoint = TestAccess::GetEndpoint(state); From 2d0f8571bf7ee02e7eb141fbce6ef56656f43371 Mon Sep 17 00:00:00 2001 From: Marian CHEREJI <122872376+marian-chereji-nxp@users.noreply.github.com> Date: Wed, 22 Jan 2025 22:05:14 +0200 Subject: [PATCH 02/40] [NXP][examples][mcxw71_k32w1] Remove "LittleFS" based key storage build option (#37157) The components required in order to support LittleFS based key storage in Matter applications are no longer available in NXP SDK 3.0. Moreover, since the migration to the (Zephyr) NVS based key storage is complete, LittleFS based key storage can now be removed from the build options. Signed-off-by: Marian Chereji --- examples/contact-sensor-app/nxp/k32w1/BUILD.gn | 8 -------- examples/contact-sensor-app/nxp/k32w1/args.gni | 2 -- examples/contact-sensor-app/nxp/mcxw71/BUILD.gn | 8 -------- examples/contact-sensor-app/nxp/mcxw71/args.gni | 2 -- examples/lighting-app/nxp/k32w1/BUILD.gn | 8 -------- examples/lighting-app/nxp/k32w1/args.gni | 2 -- examples/lighting-app/nxp/mcxw71/BUILD.gn | 8 -------- examples/lighting-app/nxp/mcxw71/args.gni | 2 -- examples/lock-app/nxp/k32w1/BUILD.gn | 8 -------- examples/lock-app/nxp/mcxw71/BUILD.gn | 8 -------- .../platform/nxp/mcxw71_k32w1/app/support/BUILD.gn | 2 -- src/platform/nxp/mcxw71_k32w1/BUILD.gn | 12 ------------ src/platform/nxp/mcxw71_k32w1/args.gni | 1 + 13 files changed, 1 insertion(+), 70 deletions(-) diff --git a/examples/contact-sensor-app/nxp/k32w1/BUILD.gn b/examples/contact-sensor-app/nxp/k32w1/BUILD.gn index c96f9676b2336a..e3694a5c44359b 100644 --- a/examples/contact-sensor-app/nxp/k32w1/BUILD.gn +++ b/examples/contact-sensor-app/nxp/k32w1/BUILD.gn @@ -86,14 +86,6 @@ mcxw71_k32w1_sdk("sdk") { defines += [ "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setup_discriminator}", ] - - if (nxp_nvm_component == "littlefs") { - include_dirs += [ "${example_platform_dir}/board" ] - sources += [ - "${example_platform_dir}/board/peripherals.c", - "${example_platform_dir}/board/peripherals.h", - ] - } } mcxw71_k32w1_executable("contact_sensor_app") { diff --git a/examples/contact-sensor-app/nxp/k32w1/args.gni b/examples/contact-sensor-app/nxp/k32w1/args.gni index ee29002e00acec..363718f1a8bbab 100644 --- a/examples/contact-sensor-app/nxp/k32w1/args.gni +++ b/examples/contact-sensor-app/nxp/k32w1/args.gni @@ -42,5 +42,3 @@ chip_openthread_ftd = false nxp_enable_ot_cli = false chip_with_diag_logs_demo = true - -nxp_nvm_component = "nvs" diff --git a/examples/contact-sensor-app/nxp/mcxw71/BUILD.gn b/examples/contact-sensor-app/nxp/mcxw71/BUILD.gn index 48719dbc9bd6e9..d0c6109ce4b676 100644 --- a/examples/contact-sensor-app/nxp/mcxw71/BUILD.gn +++ b/examples/contact-sensor-app/nxp/mcxw71/BUILD.gn @@ -85,14 +85,6 @@ mcxw71_k32w1_sdk("sdk") { defines += [ "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setup_discriminator}", ] - - if (nxp_nvm_component == "littlefs") { - include_dirs += [ "${example_platform_dir}/board" ] - sources += [ - "${example_platform_dir}/board/peripherals.c", - "${example_platform_dir}/board/peripherals.h", - ] - } } mcxw71_k32w1_executable("contact_sensor_app") { diff --git a/examples/contact-sensor-app/nxp/mcxw71/args.gni b/examples/contact-sensor-app/nxp/mcxw71/args.gni index 87a3b49632752a..bf06f4e4948fb3 100644 --- a/examples/contact-sensor-app/nxp/mcxw71/args.gni +++ b/examples/contact-sensor-app/nxp/mcxw71/args.gni @@ -40,5 +40,3 @@ chip_openthread_ftd = false nxp_enable_ot_cli = false chip_with_diag_logs_demo = true - -nxp_nvm_component = "nvs" diff --git a/examples/lighting-app/nxp/k32w1/BUILD.gn b/examples/lighting-app/nxp/k32w1/BUILD.gn index 91f069732282aa..e66b9c3bf2d3e4 100644 --- a/examples/lighting-app/nxp/k32w1/BUILD.gn +++ b/examples/lighting-app/nxp/k32w1/BUILD.gn @@ -100,14 +100,6 @@ mcxw71_k32w1_sdk("sdk") { defines += [ "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setup_discriminator}", ] - - if (nxp_nvm_component == "littlefs") { - include_dirs += [ "${example_platform_dir}/board" ] - sources += [ - "${example_platform_dir}/board/peripherals.c", - "${example_platform_dir}/board/peripherals.h", - ] - } } mcxw71_k32w1_executable("light_app") { diff --git a/examples/lighting-app/nxp/k32w1/args.gni b/examples/lighting-app/nxp/k32w1/args.gni index 078847b98268de..3d026f1fb48e9d 100644 --- a/examples/lighting-app/nxp/k32w1/args.gni +++ b/examples/lighting-app/nxp/k32w1/args.gni @@ -35,7 +35,5 @@ chip_system_config_provide_statistics = false chip_system_config_use_open_thread_inet_endpoints = true chip_with_lwip = false -nxp_nvm_component = "nvs" - nxp_use_smu2_static = true nxp_use_smu2_dynamic = true diff --git a/examples/lighting-app/nxp/mcxw71/BUILD.gn b/examples/lighting-app/nxp/mcxw71/BUILD.gn index 8ee1b50b361ea4..815f95debd93fd 100644 --- a/examples/lighting-app/nxp/mcxw71/BUILD.gn +++ b/examples/lighting-app/nxp/mcxw71/BUILD.gn @@ -100,14 +100,6 @@ mcxw71_k32w1_sdk("sdk") { defines += [ "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setup_discriminator}", ] - - if (nxp_nvm_component == "littlefs") { - include_dirs += [ "${example_platform_dir}/board" ] - sources += [ - "${example_platform_dir}/board/peripherals.c", - "${example_platform_dir}/board/peripherals.h", - ] - } } mcxw71_k32w1_executable("light_app") { diff --git a/examples/lighting-app/nxp/mcxw71/args.gni b/examples/lighting-app/nxp/mcxw71/args.gni index 5e8897a0d718a6..6be04211091da2 100644 --- a/examples/lighting-app/nxp/mcxw71/args.gni +++ b/examples/lighting-app/nxp/mcxw71/args.gni @@ -35,7 +35,5 @@ chip_system_config_provide_statistics = false chip_system_config_use_open_thread_inet_endpoints = true chip_with_lwip = false -nxp_nvm_component = "nvs" - nxp_use_smu2_static = true nxp_use_smu2_dynamic = true diff --git a/examples/lock-app/nxp/k32w1/BUILD.gn b/examples/lock-app/nxp/k32w1/BUILD.gn index d54a69400bfbf4..ba1d9053ce8767 100644 --- a/examples/lock-app/nxp/k32w1/BUILD.gn +++ b/examples/lock-app/nxp/k32w1/BUILD.gn @@ -85,14 +85,6 @@ mcxw71_k32w1_sdk("sdk") { "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setup_discriminator}", ] - if (nxp_nvm_component == "littlefs") { - include_dirs += [ "${example_platform_dir}/board" ] - sources += [ - "${example_platform_dir}/board/peripherals.c", - "${example_platform_dir}/board/peripherals.h", - ] - } - if (nxp_multiple_ble_connections) { include_dirs += [ "${example_platform_dir}/app_ble/include" ] defines += [ diff --git a/examples/lock-app/nxp/mcxw71/BUILD.gn b/examples/lock-app/nxp/mcxw71/BUILD.gn index 57328e2da8f8af..f49e938aa7ee27 100644 --- a/examples/lock-app/nxp/mcxw71/BUILD.gn +++ b/examples/lock-app/nxp/mcxw71/BUILD.gn @@ -85,14 +85,6 @@ mcxw71_k32w1_sdk("sdk") { "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setup_discriminator}", ] - if (nxp_nvm_component == "littlefs") { - include_dirs += [ "${example_platform_dir}/board" ] - sources += [ - "${example_platform_dir}/board/peripherals.c", - "${example_platform_dir}/board/peripherals.h", - ] - } - if (nxp_multiple_ble_connections) { include_dirs += [ "${example_platform_dir}/app_ble/include" ] defines += [ diff --git a/examples/platform/nxp/mcxw71_k32w1/app/support/BUILD.gn b/examples/platform/nxp/mcxw71_k32w1/app/support/BUILD.gn index 1034d91febf465..1c1c3357a5a70a 100644 --- a/examples/platform/nxp/mcxw71_k32w1/app/support/BUILD.gn +++ b/examples/platform/nxp/mcxw71_k32w1/app/support/BUILD.gn @@ -55,8 +55,6 @@ source_set("freertos_memory_utils") { if (nxp_nvm_component == "fwk_nvm") { defines = [ "CHIP_PLAT_NVM_SUPPORT=1" ] - } else if (nxp_nvm_component == "littlefs") { - defines = [ "CHIP_PLAT_NVM_SUPPORT=3" ] } public_configs = [ diff --git a/src/platform/nxp/mcxw71_k32w1/BUILD.gn b/src/platform/nxp/mcxw71_k32w1/BUILD.gn index ca0953b1b10ca9..e3a9052908a128 100644 --- a/src/platform/nxp/mcxw71_k32w1/BUILD.gn +++ b/src/platform/nxp/mcxw71_k32w1/BUILD.gn @@ -123,18 +123,6 @@ static_library("nxp_platform") { "ram_storage.c", "ram_storage.h", ] - } else if (nxp_nvm_component == "littlefs") { - defines += [ - "CHIP_PLAT_NVM_SUPPORT=3", - "EXTERNAL_KEYVALUESTOREMANAGERIMPL_HEADER=\"platform/nxp/common/KeyValueStoreManagerImpl.h\"", - ] - - sources += [ - "../common/KeyValueStoreManagerImpl.cpp", - "../common/KeyValueStoreManagerImpl.h", - "../common/NXPConfig.h", - "../common/NXPConfigKS.cpp", - ] } else if (nxp_nvm_component == "nvs") { defines += [ "gAppNvsExternalFlash_c=0", diff --git a/src/platform/nxp/mcxw71_k32w1/args.gni b/src/platform/nxp/mcxw71_k32w1/args.gni index 50cfbaba96ecb3..7ec8fdf3d56e57 100644 --- a/src/platform/nxp/mcxw71_k32w1/args.gni +++ b/src/platform/nxp/mcxw71_k32w1/args.gni @@ -21,6 +21,7 @@ openthread_root = nxp_platform = "mcxw71_k32w1" nxp_sdk_name = "mcxw71_k32w1_sdk" nxp_device_layer = "nxp/${nxp_platform}" +nxp_nvm_component = "nvs" nxp_use_lwip = false # ARM architecture flags will be set based on NXP board. From 789e941e8eef61279bfeb85607a322e494f8c12d Mon Sep 17 00:00:00 2001 From: C Freeman Date: Wed, 22 Jan 2025 17:08:29 -0500 Subject: [PATCH 03/40] Update DM XML generation script to use new path format (#37148) * Update DM XML generation script to use new path format * Restyled by isort * Remove unused import --------- Co-authored-by: Restyled.io --- scripts/spec_xml/generate_spec_xml.py | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/scripts/spec_xml/generate_spec_xml.py b/scripts/spec_xml/generate_spec_xml.py index e9fd4521ca6e09..e6a772246838d5 100755 --- a/scripts/spec_xml/generate_spec_xml.py +++ b/scripts/spec_xml/generate_spec_xml.py @@ -19,21 +19,18 @@ import os import re import subprocess -import sys import xml.etree.ElementTree as ElementTree from pathlib import Path import click -from paths import Branch, get_chip_root, get_data_model_path, get_documentation_file_path, get_in_progress_defines +from chip.testing.spec_parsing import build_xml_clusters +from paths import get_chip_root, get_documentation_file_path, get_in_progress_defines # Use the get_in_progress_defines() function to fetch the in-progress defines CURRENT_IN_PROGRESS_DEFINES = get_in_progress_defines() # Replace hardcoded paths with dynamic paths using paths.py functions DEFAULT_CHIP_ROOT = get_chip_root() -DEFAULT_OUTPUT_DIR_1_4 = get_data_model_path(Branch.V1_4) -DEFAULT_OUTPUT_DIR_IN_PROGRESS = get_data_model_path(Branch.IN_PROGRESS) -DEFAULT_OUTPUT_DIR_TOT = get_data_model_path(Branch.MASTER) DEFAULT_DOCUMENTATION_FILE = get_documentation_file_path() @@ -71,6 +68,7 @@ def make_asciidoc(target: str, include_in_progress: str, spec_dir: str, dry_run: help='Path to the spec root') @click.option( '--output-dir', + required=True, help='Path to output xml files') @click.option( '--dry-run', @@ -81,9 +79,6 @@ def make_asciidoc(target: str, include_in_progress: str, spec_dir: str, dry_run: '--include-in-progress', type=click.Choice(['All', 'None', 'Current']), default='All') def main(scraper, spec_root, output_dir, dry_run, include_in_progress): - if not output_dir: - output_dir_map = {'All': DEFAULT_OUTPUT_DIR_TOT, 'None': DEFAULT_OUTPUT_DIR_1_4, 'Current': DEFAULT_OUTPUT_DIR_IN_PROGRESS} - output_dir = output_dir_map[include_in_progress] scrape_clusters(scraper, spec_root, output_dir, dry_run, include_in_progress) scrape_device_types(scraper, spec_root, output_dir, dry_run, include_in_progress) if not dry_run: @@ -195,18 +190,12 @@ def dump_versions(scraper, spec_root, output_dir): def dump_cluster_ids(output_dir): - python_testing_path = os.path.abspath( - os.path.join(DEFAULT_CHIP_ROOT, 'src', 'python_testing')) - sys.path.insert(0, python_testing_path) clusters_output_dir = os.path.abspath( os.path.join(output_dir, 'clusters')) - - from spec_parsing_support import build_xml_clusters - header = '# List of currently defined spec clusters\n' header += 'This file was **AUTOMATICALLY** generated by `python scripts/generate_spec_xml.py`. DO NOT EDIT BY HAND!\n\n' - clusters, problems = build_xml_clusters(clusters_output_dir) + clusters, problems = build_xml_clusters(Path(clusters_output_dir)) all_name_lens = [len(c.name) for c in clusters.values()] name_len = max(all_name_lens) title_id_decimal = ' ID (Decimal) ' From c7024d33d3b48461a3ac2af20f0ed5795bf92357 Mon Sep 17 00:00:00 2001 From: Marius Tache <102153746+marius-alex-tache@users.noreply.github.com> Date: Thu, 23 Jan 2025 00:21:10 +0200 Subject: [PATCH 04/40] [NXP] Add ota gn file & minor fixes (#37121) * [openthread][mcxw71] Add ot-nxp platform file as include directory Signed-off-by: marius-alex-tache * [platform][mcxw71] Remove unused openthread dep in mbedtls config file Signed-off-by: marius-alex-tache * [platform][common] Add ota.gni to be reused by platform layer List some OTA files in an organized manner to avoid duplication in other gn files. Signed-off-by: marius-alex-tache * [platform][mcxw71] Use ota.gni Signed-off-by: marius-alex-tache * Restyled by clang-format * Restyled by gn --------- Signed-off-by: marius-alex-tache Co-authored-by: Restyled.io --- src/platform/nxp/common/ota/ota.gni | 35 ++++++++++++++++++ src/platform/nxp/mcxw71_k32w1/BUILD.gn | 24 +++++-------- .../mcxw71_k32w1/k32w1-chip-mbedtls-config.h | 36 ------------------- .../platforms/nxp/mcxw71_k32w1/BUILD.gn | 12 ++++--- 4 files changed, 50 insertions(+), 57 deletions(-) create mode 100644 src/platform/nxp/common/ota/ota.gni diff --git a/src/platform/nxp/common/ota/ota.gni b/src/platform/nxp/common/ota/ota.gni new file mode 100644 index 00000000000000..9bb621f56282c3 --- /dev/null +++ b/src/platform/nxp/common/ota/ota.gni @@ -0,0 +1,35 @@ +# Copyright (c) 2025 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/nxp_sdk.gni") +import("${nxp_sdk_build_root}/nxp_sdk.gni") + +ota_root = get_path_info(".", "abspath") + +ota_sources = [ + "${ota_root}/OTAFirmwareProcessor.cpp", + "${ota_root}/OTAFirmwareProcessor.h", + "${ota_root}/OTAHooks.cpp", + "${ota_root}/OTAImageProcessorImpl.cpp", + "${ota_root}/OTAImageProcessorImpl.h", + "${ota_root}/OTATlvProcessor.cpp", + "${ota_root}/OTATlvProcessor.h", +] + +if (nxp_use_factory_data && nxp_enable_ota_factory_data_processor) { + ota_sources += [ + "${ota_root}/OTAFactoryDataProcessor.cpp", + "${ota_root}/OTAFactoryDataProcessor.h", + ] +} diff --git a/src/platform/nxp/mcxw71_k32w1/BUILD.gn b/src/platform/nxp/mcxw71_k32w1/BUILD.gn index e3a9052908a128..df4a711f691371 100644 --- a/src/platform/nxp/mcxw71_k32w1/BUILD.gn +++ b/src/platform/nxp/mcxw71_k32w1/BUILD.gn @@ -18,6 +18,7 @@ import("//build_overrides/openthread.gni") import("${chip_root}/src/crypto/crypto.gni") import("${chip_root}/src/platform/device.gni") +import("${chip_root}/src/platform/nxp/common/ota/ota.gni") import("${nxp_sdk_build_root}/nxp_sdk.gni") @@ -53,22 +54,7 @@ source_set("nxp_factory_data") { source_set("nxp_ota") { public = [ "../common/ota/OTAImageProcessorImpl.h" ] - sources = [ - "../common/ota/OTAFirmwareProcessor.cpp", - "../common/ota/OTAFirmwareProcessor.h", - "../common/ota/OTAHooks.cpp", - "../common/ota/OTAImageProcessorImpl.cpp", - "../common/ota/OTAImageProcessorImpl.h", - "../common/ota/OTATlvProcessor.cpp", - "../common/ota/OTATlvProcessor.h", - ] - - if (nxp_use_factory_data && nxp_enable_ota_factory_data_processor) { - sources += [ - "../common/ota/OTAFactoryDataProcessor.cpp", - "../common/ota/OTAFactoryDataProcessor.h", - ] - } + sources = ota_sources deps = [ ":nxp_platform", @@ -138,6 +124,12 @@ static_library("nxp_platform") { ] } + # When the app is built using cmake, we must ensure the OTA platform files are also compiled. + # When the app is built using gn, the app selects the nxp_ota target through its build file. + if (nxp_external_sdk && chip_enable_ota_requestor) { + sources += ota_sources + } + if (nxp_use_plain_dac_key) { defines += [ "CHIP_USE_PLAIN_DAC_KEY=1" ] } else { diff --git a/src/platform/nxp/mcxw71_k32w1/k32w1-chip-mbedtls-config.h b/src/platform/nxp/mcxw71_k32w1/k32w1-chip-mbedtls-config.h index f3d9949f730df0..ef244a7f4da479 100644 --- a/src/platform/nxp/mcxw71_k32w1/k32w1-chip-mbedtls-config.h +++ b/src/platform/nxp/mcxw71_k32w1/k32w1-chip-mbedtls-config.h @@ -19,15 +19,9 @@ #ifndef MBEDTLS_CONFIG_H #define MBEDTLS_CONFIG_H -#include "openthread-core-config.h" - #include #include -#include -#include -#include - #undef MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES #define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf @@ -67,16 +61,6 @@ #define MBEDTLS_SSL_PROTO_DTLS #define MBEDTLS_SSL_TLS_C -#if OPENTHREAD_CONFIG_BORDER_AGENT_ENABLE || OPENTHREAD_CONFIG_COMMISSIONER_ENABLE || OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE -#define MBEDTLS_SSL_COOKIE_C -#define MBEDTLS_SSL_SRV_C -#endif - -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE -#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED -#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED -#endif - #ifdef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED #define MBEDTLS_BASE64_C #define MBEDTLS_ECDH_C @@ -87,16 +71,6 @@ #define MBEDTLS_X509_CRT_PARSE_C #endif -#if OPENTHREAD_CONFIG_ECDSA_ENABLE -#define MBEDTLS_BASE64_C -#define MBEDTLS_ECDH_C -#define MBEDTLS_ECDSA_C -#define MBEDTLS_ECDSA_DETERMINISTIC -#define MBEDTLS_OID_C -#define MBEDTLS_PEM_PARSE_C -#define MBEDTLS_PK_WRITE_C -#endif - #define MBEDTLS_MPI_WINDOW_SIZE 1 /**< Maximum windows size used. */ #define MBEDTLS_MPI_MAX_SIZE 32 /**< Maximum number of bytes for usable MPIs. */ #define MBEDTLS_ECP_MAX_BITS 256 /**< Maximum bit size of groups */ @@ -104,19 +78,9 @@ #define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 /**< Enable fixed-point speed-up */ #define MBEDTLS_ENTROPY_MAX_SOURCES 2 /**< Maximum number of sources supported */ -#if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE -#define MBEDTLS_PLATFORM_STD_CALLOC otPlatCAlloc /**< Default allocator to use, can be undefined */ -#define MBEDTLS_PLATFORM_STD_FREE otPlatFree /**< Default free to use, can be undefined */ -#else #define MBEDTLS_MEMORY_BUFFER_ALLOC_C -#endif -#if OPENTHREAD_CONFIG_COAP_SECURE_API_ENABLE -#define MBEDTLS_SSL_MAX_CONTENT_LEN 900 /**< Maxium fragment length in bytes */ -#else #define MBEDTLS_SSL_MAX_CONTENT_LEN 768 /**< Maxium fragment length in bytes */ -#endif - #define MBEDTLS_SSL_IN_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN #define MBEDTLS_SSL_OUT_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN #define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 diff --git a/third_party/openthread/platforms/nxp/mcxw71_k32w1/BUILD.gn b/third_party/openthread/platforms/nxp/mcxw71_k32w1/BUILD.gn index 2050591b8f4345..2bbfc4fae4b03a 100644 --- a/third_party/openthread/platforms/nxp/mcxw71_k32w1/BUILD.gn +++ b/third_party/openthread/platforms/nxp/mcxw71_k32w1/BUILD.gn @@ -24,7 +24,10 @@ import("${nxp_sdk_build_root}/nxp_sdk.gni") openthread_nxp_root = "${chip_root}/third_party/openthread/ot-nxp" config("openthread_k32w1_config") { - include_dirs = [ "${openthread_nxp_root}/src/k32w1" ] + include_dirs = [ + "${openthread_nxp_root}/src/k32w1", + "${openthread_nxp_root}/src/mcxw71", + ] defines = [ "OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE=1", @@ -111,10 +114,9 @@ source_set("libopenthread-k32w1") { "../..:libopenthread-platform-utils", ] + public_deps += [ "${nxp_sdk_build_root}:nxp_mbedtls" ] + if (!nxp_external_sdk) { - public_deps += [ - "${nxp_sdk_build_root}:nxp_mbedtls", - nxp_sdk_target, - ] + public_deps += [ nxp_sdk_target ] } } From 30508e484ae9a0b33d840f150fbe04b1ac4e57cd Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Wed, 22 Jan 2025 23:22:27 +0100 Subject: [PATCH 05/40] Re-validate submodules when labels are modified (#37101) * Re-validate submodules when labels are modified * Reformat help text --- .github/workflows/third-party-check.yaml | 3 ++- third_party/tizen/tizen_qemu.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/third-party-check.yaml b/.github/workflows/third-party-check.yaml index beda0af41b0622..ad072da755892f 100644 --- a/.github/workflows/third-party-check.yaml +++ b/.github/workflows/third-party-check.yaml @@ -21,6 +21,7 @@ on: paths: - "third_party/**" - ".gitmodules" + types: [opened, synchronize, reopened, labeled, unlabeled] jobs: check-submodule-update-label: @@ -32,7 +33,7 @@ jobs: run: | echo This pull request attempts to update submodules without the changing-submodules-on-purpose label. Please apply that label if the changes are intentional, or remove those changes. exit 1 - - if: ${{ contains(github.event.pull_request.labels.*.name, 'changing-submodules-on-purpose') }} + - if: ${{ contains(github.event.pull_request.labels.*.name, 'changing-submodules-on-purpose') }} name: Success run: | echo PR looks good. diff --git a/third_party/tizen/tizen_qemu.py b/third_party/tizen/tizen_qemu.py index 7b7eb412a23c04..78c840b404a2de 100755 --- a/third_party/tizen/tizen_qemu.py +++ b/third_party/tizen/tizen_qemu.py @@ -69,7 +69,8 @@ help=("host directory to share with the guest")) parser.add_argument( '--runner', type=str, - help=("path to the runner script which will run automatically after boot. path should be relative to shared directory")) + help=("path to the runner script which will be executed after boot; " + "it should be relative to the shared directory")) parser.add_argument( '--output', metavar='FILE', default="/dev/null", help="store the QEMU output in a FILE") From 4412d0c43c3c8c9d18a07c94a874324be824e503 Mon Sep 17 00:00:00 2001 From: Pradip De Date: Wed, 22 Jan 2025 22:54:18 +0000 Subject: [PATCH 06/40] Update VideoStreamModify command in CameraAVStreamMgmt xml. (#37016) Minor modification in the command description to account for the removal of an argument in the Spec. --- .../data-model/chip/camera-av-stream-management-cluster.xml | 6 +++--- src/controller/data_model/controller-clusters.matter | 2 +- src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/zap-templates/zcl/data-model/chip/camera-av-stream-management-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/camera-av-stream-management-cluster.xml index 6182aba244808f..0a5110ec402bcc 100644 --- a/src/app/zap-templates/zcl/data-model/chip/camera-av-stream-management-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/camera-av-stream-management-cluster.xml @@ -1,6 +1,6 @@ @@ -508,7 +508,7 @@ Git: 1.4-446-g4a179b5f4 - This command SHALL be used to modify the resolution of a stream specified by the VideoStreamID. + This command SHALL be used to modify a stream specified by the VideoStreamID. diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 69dd7b62df393a..1ba302c3851e42 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -9823,7 +9823,7 @@ provisional cluster CameraAvStreamManagement = 1361 { command access(invoke: manage) AudioStreamDeallocate(AudioStreamDeallocateRequest): DefaultSuccess = 2; /** This command SHALL allocate a video stream on the camera and return an allocated video stream identifier. */ command access(invoke: manage) VideoStreamAllocate(VideoStreamAllocateRequest): VideoStreamAllocateResponse = 3; - /** This command SHALL be used to modify the resolution of a stream specified by the VideoStreamID. */ + /** This command SHALL be used to modify a stream specified by the VideoStreamID. */ command access(invoke: manage) VideoStreamModify(VideoStreamModifyRequest): DefaultSuccess = 5; /** This command SHALL deallocate a video stream on the camera, corresponding to the given video stream identifier. */ command access(invoke: manage) VideoStreamDeallocate(VideoStreamDeallocateRequest): DefaultSuccess = 6; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index 8193460364759d..54e4e59c1e5a68 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -14086,7 +14086,7 @@ MTR_PROVISIONALLY_AVAILABLE /** * Command VideoStreamModify * - * This command SHALL be used to modify the resolution of a stream specified by the VideoStreamID. + * This command SHALL be used to modify a stream specified by the VideoStreamID. */ - (void)videoStreamModifyWithParams:(MTRCameraAVStreamManagementClusterVideoStreamModifyParams *)params completion:(MTRStatusCompletion)completion MTR_PROVISIONALLY_AVAILABLE; /** From 57ff3e69e00938253094e5eaf603761ce83de329 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Wed, 22 Jan 2025 16:33:33 -0800 Subject: [PATCH 07/40] We should only validate against None when optional=true (#37161) --- src/python_testing/TC_DGWIFI_2_1.py | 89 +++++++++++------------------ 1 file changed, 34 insertions(+), 55 deletions(-) diff --git a/src/python_testing/TC_DGWIFI_2_1.py b/src/python_testing/TC_DGWIFI_2_1.py index 3012baa153d716..707deb0198047f 100644 --- a/src/python_testing/TC_DGWIFI_2_1.py +++ b/src/python_testing/TC_DGWIFI_2_1.py @@ -64,15 +64,10 @@ def is_valid_bssid(bssid) -> bool: return False def assert_valid_bssid(self, value, field_name): - """Asserts that the value is a valid BSSID (MAC address), None, or NullValue.""" - if isinstance(value, Nullable): - if value == NullValue: - return - value = value.Value - - if value is not None: + """Asserts that the value is a valid BSSID (MAC address), or NullValue.""" + if value is not NullValue: asserts.assert_true(self.is_valid_bssid(value), - f"{field_name} should be a valid BSSID string (e.g., '00:11:22:33:44:55') or None/NullValue.") + f"{field_name} should be a valid BSSID string (e.g., '00:11:22:33:44:55') or NullValue.") async def read_dgwifi_attribute_expect_success(self, endpoint, attribute): cluster = Clusters.Objects.WiFiNetworkDiagnostics @@ -134,26 +129,22 @@ async def test_TC_DGWIFI_2_1(self): # SecurityType is an enum. If the interface is not operational, it could be NULL. # If not NULL, we expect an integer in the SecurityType enum range. # Just do a minimal check here; you can refine or extend based on the spec. - if security_type is not None: - asserts.assert_true(isinstance(security_type, Nullable), - "SecurityType must be of type 'Nullable' when not None.") - - if security_type is not NullValue: - security_type_value = security_type.Value - self.assert_valid_uint8(security_type_value, "SecurityType") - - # Check if the security_type is a valid SecurityTypeEnum member - self.assert_true( - security_type_value in [item.value for item in Clusters.Objects.WiFiNetworkDiagnostics.Enums.SecurityTypeEnum], - f"SecurityType {security_type_value} is not a valid SecurityTypeEnum value" - ) - - # Additional check that it's not kUnknownEnumValue: - self.assert_true( - security_type_value != Clusters.Objects.WiFiNetworkDiagnostics.Enums.SecurityTypeEnum.kUnknownEnumValue.value, - f"SecurityType should not be kUnknownEnumValue " - f"({Clusters.Objects.WiFiNetworkDiagnostics.Enums.SecurityTypeEnum.kUnknownEnumValue.value})" - ) + if security_type is not NullValue: + security_type_value = security_type.Value + self.assert_valid_uint8(security_type_value, "SecurityType") + + # Check if the security_type is a valid SecurityTypeEnum member + self.assert_true( + security_type_value in [item.value for item in Clusters.Objects.WiFiNetworkDiagnostics.Enums.SecurityTypeEnum], + f"SecurityType {security_type_value} is not a valid SecurityTypeEnum value" + ) + + # Additional check that it's not kUnknownEnumValue: + self.assert_true( + security_type_value != Clusters.Objects.WiFiNetworkDiagnostics.Enums.SecurityTypeEnum.kUnknownEnumValue.value, + f"SecurityType should not be kUnknownEnumValue " + f"({Clusters.Objects.WiFiNetworkDiagnostics.Enums.SecurityTypeEnum.kUnknownEnumValue.value})" + ) # # STEP 4: TH reads WiFiVersion attribute @@ -161,21 +152,17 @@ async def test_TC_DGWIFI_2_1(self): self.step(4) wifi_version = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.WiFiVersion) # WiFiVersion is an enum. If not configured or operational, might be NULL. - if wifi_version is not None: - asserts.assert_true(isinstance(wifi_version, Nullable), - "WiFiVersion must be of type 'Nullable' when not None.") - - if wifi_version is not NullValue: - wifi_version_value = wifi_version.Value - self.assert_valid_uint8(wifi_version_value, "WiFiVersion") + if wifi_version is not NullValue: + wifi_version_value = wifi_version.Value + self.assert_valid_uint8(wifi_version_value, "WiFiVersion") - # Check if the wifi_version is a valid WiFiVersionEnum member - self.assert_true(wifi_version_value in [item.value for item in Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum], - f"WiFiVersion {wifi_version_value} is not a valid WiFiVersionEnum value") + # Check if the wifi_version is a valid WiFiVersionEnum member + self.assert_true(wifi_version_value in [item.value for item in Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum], + f"WiFiVersion {wifi_version_value} is not a valid WiFiVersionEnum value") - # Additional check that it's not kUnknownEnumValue: - self.assert_true(wifi_version_value != Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum.kUnknownEnumValue.value, - f"WiFiVersion should not be kUnknownEnumValue ({Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum.kUnknownEnumValue.value})") + # Additional check that it's not kUnknownEnumValue: + self.assert_true(wifi_version_value != Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum.kUnknownEnumValue.value, + f"WiFiVersion should not be kUnknownEnumValue ({Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum.kUnknownEnumValue.value})") # # STEP 5: TH reads ChannelNumber attribute @@ -183,12 +170,8 @@ async def test_TC_DGWIFI_2_1(self): self.step(5) channel_number = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.ChannelNumber) # If not operational, might be NULL. Else we expect an unsigned integer channel. - if channel_number is not None: - asserts.assert_true(isinstance(channel_number, Nullable), - "ChannelNumber must be of type 'Nullable' when not None.") - - if channel_number is not NullValue: - self.assert_valid_uint16(channel_number.Value, "ChannelNumber") + if channel_number is not NullValue: + self.assert_valid_uint16(channel_number.Value, "ChannelNumber") # # STEP 6: TH reads RSSI attribute @@ -196,14 +179,10 @@ async def test_TC_DGWIFI_2_1(self): self.step(6) rssi = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.Rssi) # RSSI is typically a signed integer (dB). If not operational, might be NULL. - if rssi is not None: - asserts.assert_true(isinstance(rssi, Nullable), - "RSSI must be of type 'Nullable' when not None.") - - if rssi is not NullValue: - rssi_value = rssi.Value - asserts.assert_true(isinstance(rssi_value, int) and -120 <= rssi_value <= 0, - "rssi_value is not within valid range.") + if rssi is not NullValue: + rssi_value = rssi.Value + asserts.assert_true(isinstance(rssi_value, int) and -120 <= rssi_value <= 0, + "rssi_value is not within valid range.") # # STEP 7: TH reads BeaconLostCount attribute From c29c15c094562baabd254cf69d27a29cc3ee43ef Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Thu, 23 Jan 2025 16:04:54 +0530 Subject: [PATCH 08/40] =?UTF-8?q?da=5Frevocation:=20fix=20serial=20number?= =?UTF-8?q?=20formatting=20in=20revocation=20set=20generat=E2=80=A6=20(#37?= =?UTF-8?q?104)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * da_revocation: fix serial number formatting in revocation set generation script Also update test data to ensure 2-byte alignment * add comment explaining the change * update comment --- credentials/generate_revocation_set.py | 8 +++++++- .../revocation-sets/revocation-set-for-pai.json | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/credentials/generate_revocation_set.py b/credentials/generate_revocation_set.py index 3765439e02ee97..afd69dcc1dd669 100755 --- a/credentials/generate_revocation_set.py +++ b/credentials/generate_revocation_set.py @@ -240,7 +240,13 @@ def generate_revocation_set_from_crl(crl_file: x509.CertificateRevocationList, except Exception: pass - serialnumber_list.append(bytes(str('{:02X}'.format(revoked_cert.serial_number)), 'utf-8').decode('utf-8')) + # Ensure the serial number is always a 2-byte aligned hex string. + # TestDACRevocationDelegateImpl encodes the serial number as an even-length hex string + # using BytesToHex in src/lib/support/BytesToHex.cpp. + # As the primary consumer of this data, we should use the same here. + serialnumber = '{:02X}'.format(revoked_cert.serial_number) + serialnumber = serialnumber if len(serialnumber) % 2 == 0 else '0' + serialnumber + serialnumber_list.append(serialnumber) entry = { "type": "revocation_set", diff --git a/credentials/test/revoked-attestation-certificates/revocation-sets/revocation-set-for-pai.json b/credentials/test/revoked-attestation-certificates/revocation-sets/revocation-set-for-pai.json index 6bf0d6f5ddd3c0..46c3c1b66cddd8 100644 --- a/credentials/test/revoked-attestation-certificates/revocation-sets/revocation-set-for-pai.json +++ b/credentials/test/revoked-attestation-certificates/revocation-sets/revocation-set-for-pai.json @@ -4,7 +4,7 @@ "issuer_subject_key_id": "63540E47F64B1C38D13884A462D16C195D8FFB3C", "issuer_name": "MD0xJTAjBgNVBAMMHE1hdHRlciBEZXYgUEFJIDB4RkZGMSBubyBQSUQxFDASBgorBgEEAYKifAIBDARGRkYx", "revoked_serial_numbers": [ - "AB042494323FE54", + "0AB042494323FE54", "19367D978EAC533A", "2569383D24BB36EA" ], From 17ad72e363c580ccd3dc164cd096da877c65cbaf Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Thu, 23 Jan 2025 04:32:15 -0800 Subject: [PATCH 09/40] Pin the Restyler version to v0.6.0.2 (#37169) * Pin the Restyler version to v0.6.0.2 * Remove new name tags --- .github/workflows/restyled.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/restyled.yml b/.github/workflows/restyled.yml index 9174483ecb7069..4bb39f389cf0a8 100644 --- a/.github/workflows/restyled.yml +++ b/.github/workflows/restyled.yml @@ -15,6 +15,10 @@ jobs: uses: actions/checkout@v4 - uses: restyled-io/actions/setup@v4 + with: + # Pin the Restyler version to v0.6.0.2 + tag: 'v0.6.0.2' + - id: restyler uses: restyled-io/actions/run@v4 with: From 70c473cd06db571c5536ee9efb2b6c809abdf663 Mon Sep 17 00:00:00 2001 From: cdj <45139296+DejinChen@users.noreply.github.com> Date: Thu, 23 Jan 2025 22:07:21 +0800 Subject: [PATCH 10/40] [ESP32]: Remove the same configs as defaults (#36940) * ESP32: Remove the same configs as defaults * resolve comments --- .github/workflows/examples-esp32.yaml | 10 +-- .../all-clusters-app/esp32/sdkconfig.defaults | 11 +-- .../esp32/sdkconfig.defaults.esp32c3 | 54 --------------- .../esp32/sdkconfig.defaults.esp32c6 | 62 ----------------- .../esp32/sdkconfig.defaults.esp32h2 | 56 +-------------- .../esp32/sdkconfig.defaults.esp32p4 | 23 ------- .../esp32/sdkconfig.defaults | 8 --- examples/bridge-app/esp32/sdkconfig.defaults | 7 -- .../esp32/sdkconfig.defaults | 10 +-- .../esp32/sdkconfig.defaults.esp32c6 | 65 ----------------- .../esp32/sdkconfig.defaults.esp32h2 | 59 +--------------- .../light-switch-app/esp32/sdkconfig.defaults | 13 ++-- .../esp32/sdkconfig.defaults.esp32c3 | 34 --------- .../lighting-app/esp32/sdkconfig.defaults | 10 +-- .../esp32/sdkconfig.defaults.esp32c6 | 69 ------------------- .../esp32/sdkconfig.defaults.esp32h2 | 59 +--------------- .../esp32/sdkconfig.defaults.esp32p4 | 23 ------- examples/lit-icd-app/esp32/sdkconfig.defaults | 2 - examples/lock-app/esp32/sdkconfig.defaults | 7 -- .../lock-app/esp32/sdkconfig.defaults.esp32c6 | 58 ---------------- .../ota-provider-app/esp32/sdkconfig.defaults | 8 --- .../esp32/sdkconfig.defaults | 8 --- .../esp32/sdkconfig.defaults | 7 -- examples/pigweed-app/esp32/sdkconfig.defaults | 8 --- examples/shell/esp32/sdkconfig.defaults | 8 --- .../esp32/sdkconfig.defaults | 8 --- scripts/build/builders/esp32.py | 26 +++++-- .../dry_run_esp32-devkitc-light-rpc.txt | 2 +- 28 files changed, 46 insertions(+), 669 deletions(-) diff --git a/.github/workflows/examples-esp32.yaml b/.github/workflows/examples-esp32.yaml index b41db0b4609ee4..cd626fd02669e3 100644 --- a/.github/workflows/examples-esp32.yaml +++ b/.github/workflows/examples-esp32.yaml @@ -93,7 +93,7 @@ jobs: mv scripts/codegen.py.renamed scripts/codegen.py mv scripts/tools/zap/generate.py.renamed scripts/tools/zap/generate.py - name: Build example All Clusters App(Target:ESP32C3) - run: scripts/examples/esp_example.sh all-clusters-app sdkconfig.defaults.esp32c3 esp32c3 + run: scripts/examples/esp_example.sh all-clusters-app sdkconfig.defaults esp32c3 - name: Build example All Clusters App(Target:ESP32) run: | ./scripts/run_in_build_env.sh \ @@ -114,10 +114,10 @@ jobs: /tmp/bloat_reports/ - name: Build example Lighting App (Target:ESP32H2) - run: scripts/examples/esp_example.sh lighting-app sdkconfig.defaults.esp32h2 esp32h2 + run: scripts/examples/esp_example.sh lighting-app sdkconfig.defaults esp32h2 - name: Build example Lighting App (Target:ESP32C6) - run: scripts/examples/esp_example.sh lighting-app sdkconfig.defaults.esp32c6 esp32c6 + run: scripts/examples/esp_example.sh lighting-app sdkconfig.defaults esp32c6 - name: Uploading Size Reports uses: ./.github/actions/upload-size-reports @@ -163,7 +163,7 @@ jobs: run: scripts/examples/esp_example.sh ota-provider-app sdkconfig.defaults - name: Build example Light Switch App (Target:ESP32C3) - run: scripts/examples/esp_example.sh light-switch-app sdkconfig.defaults.esp32c3 esp32c3 + run: scripts/examples/esp_example.sh light-switch-app sdkconfig.defaults esp32c3 - name: Build example Lighting App (external platform) run: scripts/examples/esp_example.sh lighting-app sdkconfig.ext_plat.defaults @@ -178,4 +178,4 @@ jobs: run: scripts/examples/esp_example.sh pigweed-app sdkconfig.defaults - name: Build example Lock App (Target:ESP32C6) - run: scripts/examples/esp_example.sh lock-app sdkconfig.defaults.esp32c6 esp32c6 + run: scripts/examples/esp_example.sh lock-app sdkconfig.defaults esp32c6 diff --git a/examples/all-clusters-app/esp32/sdkconfig.defaults b/examples/all-clusters-app/esp32/sdkconfig.defaults index ed9adcc7d82870..4dcff1583e4f87 100644 --- a/examples/all-clusters-app/esp32/sdkconfig.defaults +++ b/examples/all-clusters-app/esp32/sdkconfig.defaults @@ -19,14 +19,6 @@ # Some useful defaults for the demo app configuration. # - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - #enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y @@ -74,3 +66,6 @@ CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y CONFIG_LWIP_IPV6_NUM_ADDRESSES=6 CONFIG_MAX_GROUP_ENDPOINTS_PER_FABRIC=3 + +# Enable OTA Requestor +CONFIG_ENABLE_OTA_REQUESTOR=y diff --git a/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32c3 b/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32c3 index 8d7455d0d7610f..62c2cb2fd57f70 100644 --- a/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32c3 +++ b/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32c3 @@ -1,55 +1 @@ -# -# Copyright (c) 2020 Project CHIP Authors -# Copyright (c) 2018 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. -# -# Description: -# CI uses this to select the ESP32C3-DevKitM. -# CONFIG_IDF_TARGET="esp32c3" -CONFIG_IDF_TARGET_ESP32C3=y -CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM=y - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - -#enable BT -CONFIG_BT_ENABLED=y -CONFIG_BT_NIMBLE_ENABLED=y - -#enable lwip ipv6 autoconfig -CONFIG_LWIP_IPV6_AUTOCONFIG=y - -# Use a custom partition table -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" - -#enable lwIP route hooks -CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y -CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y - -# Serial Flasher config -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -CONFIG_ESPTOOLPY_FLASHSIZE="4MB" - -# Enable HKDF in mbedtls -CONFIG_MBEDTLS_HKDF_C=y - -# Move functions from IRAM to flash -CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y diff --git a/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32c6 b/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32c6 index 399eb5901c5c45..5844e52c9d3173 100644 --- a/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32c6 +++ b/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32c6 @@ -1,63 +1 @@ CONFIG_IDF_TARGET="esp32c6" - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_FLASHMODE_QIO=y -CONFIG_ESPTOOLPY_FLASHFREQ_40M=y -CONFIG_ESPTOOLPY_FLASHFREQ="40m" -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - -# libsodium -CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y - - -# NIMBLE -CONFIG_BT_ENABLED=y -CONFIG_BT_NIMBLE_ENABLED=y -CONFIG_BT_NIMBLE_EXT_ADV=n -CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 -CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=y - -# Disable OpenThread -CONFIG_OPENTHREAD_ENABLED=n - -# Disable lwip ipv6 autoconfig -CONFIG_LWIP_IPV6_AUTOCONFIG=y - -# Use a custom partition table -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" - -# LwIP config for OpenThread -CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 -CONFIG_LWIP_MULTICAST_PING=y - -# mbedTLS -CONFIG_MBEDTLS_HARDWARE_AES=n -CONFIG_MBEDTLS_HARDWARE_MPI=n -CONFIG_MBEDTLS_HARDWARE_SHA=n -CONFIG_MBEDTLS_HARDWARE_ECC=y -CONFIG_MBEDTLS_CMAC_C=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y -CONFIG_MBEDTLS_ECJPAKE_C=y - -# MDNS platform -CONFIG_USE_MINIMAL_MDNS=y -CONFIG_ENABLE_EXTENDED_DISCOVERY=y - -# FreeRTOS should use legacy API -CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y - -# Wi-Fi Settings -CONFIG_ENABLE_WIFI_STATION=y -# Enable this to avoid implicit declaration of function 'esp_send_assoc_resp' -CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y - -# Enable OTA Requestor -CONFIG_ENABLE_OTA_REQUESTOR=y - -# Enable chip shell -CONFIG_ENABLE_CHIP_SHELL=y diff --git a/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32h2 b/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32h2 index c1f43ab77d1207..078b7f7243987d 100644 --- a/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32h2 +++ b/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32h2 @@ -1,26 +1,4 @@ CONFIG_IDF_TARGET="esp32h2" -CONFIG_IDF_TARGET_ESP32H2_BETA_VERSION_2=y - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_FLASHMODE_QIO=y -CONFIG_ESPTOOLPY_FLASHFREQ_40M=y -CONFIG_ESPTOOLPY_FLASHFREQ="40m" -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - -# libsodium -CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y - - -# NIMBLE -CONFIG_BT_ENABLED=y -CONFIG_BT_NIMBLE_ENABLED=y -CONFIG_BT_NIMBLE_EXT_ADV=n -CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 -CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=n # Enable OpenThread CONFIG_OPENTHREAD_ENABLED=y @@ -33,45 +11,13 @@ CONFIG_OPENTHREAD_DNS_CLIENT=y # Disable lwip ipv6 autoconfig CONFIG_LWIP_IPV6_AUTOCONFIG=n -# Use a custom partition table -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" - # LwIP config for OpenThread CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 CONFIG_LWIP_MULTICAST_PING=y -# mbedTLS -CONFIG_MBEDTLS_HARDWARE_AES=n -CONFIG_MBEDTLS_HARDWARE_MPI=n -CONFIG_MBEDTLS_HARDWARE_SHA=n -CONFIG_MBEDTLS_HARDWARE_ECC=y -CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN=n -CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY=n -CONFIG_MBEDTLS_CMAC_C=y -CONFIG_MBEDTLS_SSL_PROTO_DTLS=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y - -# rtc clk for ble -# CONFIG_ESP32H2_RTC_CLK_SRC_EXT_CRYS=y - # MDNS platform CONFIG_USE_MINIMAL_MDNS=n CONFIG_ENABLE_EXTENDED_DISCOVERY=y -# FreeRTOS should use legacy API -CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y - -# Disable STA and AP for ESP32H2 +# Disable STA for ESP32H2 CONFIG_ENABLE_WIFI_STATION=n -# Enable this to avoid implicit declaration of function 'esp_send_assoc_resp' -CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y - -# Enable OTA Requestor -CONFIG_ENABLE_OTA_REQUESTOR=y - -# Enable chip shell -CONFIG_ENABLE_CHIP_SHELL=y - -# Enable HKDF in mbedtls -CONFIG_MBEDTLS_HKDF_C=y diff --git a/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32p4 b/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32p4 index 3211b306b2be99..5a5709da53ec84 100644 --- a/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32p4 +++ b/examples/all-clusters-app/esp32/sdkconfig.defaults.esp32p4 @@ -1,35 +1,12 @@ CONFIG_IDF_TARGET="esp32p4" -# Flash size and partition -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" - # Enable BLE Host but use remote controller -CONFIG_BT_ENABLED=y -CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_TRANSPORT_UART=n CONFIG_ESP_ENABLE_BT=y # Increase main task stack size CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096 -# Disable Wi-Fi Soft AP -CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n - -# LwIP -CONFIG_LWIP_IPV6_AUTOCONFIG=y -CONFIG_LWIP_IPV6_NUM_ADDRESSES=6 - -# mbedtls -CONFIG_MBEDTLS_HKDF_C=y - -# Matter shell -CONFIG_ENABLE_CHIP_SHELL=y - -# OTA requestor -CONFIG_ENABLE_OTA_REQUESTOR=y - # Do not deinit BLE after commissioning CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=n diff --git a/examples/all-clusters-minimal-app/esp32/sdkconfig.defaults b/examples/all-clusters-minimal-app/esp32/sdkconfig.defaults index c551c966de34ec..ef68a68f15ab38 100644 --- a/examples/all-clusters-minimal-app/esp32/sdkconfig.defaults +++ b/examples/all-clusters-minimal-app/esp32/sdkconfig.defaults @@ -19,14 +19,6 @@ # Some useful defaults for the demo app configuration. # - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - #enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y diff --git a/examples/bridge-app/esp32/sdkconfig.defaults b/examples/bridge-app/esp32/sdkconfig.defaults index c92a558df8491b..79c1a45fc81512 100644 --- a/examples/bridge-app/esp32/sdkconfig.defaults +++ b/examples/bridge-app/esp32/sdkconfig.defaults @@ -19,13 +19,6 @@ # Some useful defaults for the demo app configuration. # -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - #enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y diff --git a/examples/energy-management-app/esp32/sdkconfig.defaults b/examples/energy-management-app/esp32/sdkconfig.defaults index 5bcdc334fa5c78..5499f3347f0e92 100644 --- a/examples/energy-management-app/esp32/sdkconfig.defaults +++ b/examples/energy-management-app/esp32/sdkconfig.defaults @@ -18,13 +18,6 @@ # Some useful defaults for the demo app configuration. # -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - #enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y @@ -85,3 +78,6 @@ CONFIG_CHIP_DEVICE_CONFIG_ENABLE_ENERGY_REPORTING_TRIGGER=y # Ensure kPowerForecastReporting (PFR) is set in the DeviceEnergyManagement::Feature attribute. Note cannot set PFR and SFR. CONFIG_DEM_SUPPORT_POWER_FORECAST_REPORTING=y + +# Enable OTA Requestor +CONFIG_ENABLE_OTA_REQUESTOR=y diff --git a/examples/energy-management-app/esp32/sdkconfig.defaults.esp32c6 b/examples/energy-management-app/esp32/sdkconfig.defaults.esp32c6 index 6127b910506ab4..5844e52c9d3173 100644 --- a/examples/energy-management-app/esp32/sdkconfig.defaults.esp32c6 +++ b/examples/energy-management-app/esp32/sdkconfig.defaults.esp32c6 @@ -1,66 +1 @@ CONFIG_IDF_TARGET="esp32c6" - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_FLASHMODE_QIO=y -CONFIG_ESPTOOLPY_FLASHFREQ_40M=y -CONFIG_ESPTOOLPY_FLASHFREQ="40m" -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - -# libsodium -CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y - - -# NIMBLE -CONFIG_BT_ENABLED=y -CONFIG_BT_NIMBLE_ENABLED=y -CONFIG_BT_NIMBLE_EXT_ADV=n -CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 -CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=y - -# Disable OpenThread -CONFIG_OPENTHREAD_ENABLED=n - -# Disable lwip ipv6 autoconfig -CONFIG_LWIP_IPV6_AUTOCONFIG=y - -# Use a custom partition table -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" - -# LwIP config for OpenThread -CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 -CONFIG_LWIP_MULTICAST_PING=y - -# mbedTLS -CONFIG_MBEDTLS_HARDWARE_AES=n -CONFIG_MBEDTLS_HARDWARE_MPI=n -CONFIG_MBEDTLS_HARDWARE_SHA=n -CONFIG_MBEDTLS_HARDWARE_ECC=y -CONFIG_MBEDTLS_CMAC_C=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y -CONFIG_MBEDTLS_ECJPAKE_C=y - -# MDNS platform -CONFIG_USE_MINIMAL_MDNS=y -CONFIG_ENABLE_EXTENDED_DISCOVERY=y - -# FreeRTOS should use legacy API -CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y - -# Wi-Fi Settings -CONFIG_ENABLE_WIFI_STATION=y -# Enable this to avoid implicit declaration of function 'esp_send_assoc_resp' -CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y - -# Enable OTA Requestor -CONFIG_ENABLE_OTA_REQUESTOR=y - -# Enable chip shell -CONFIG_ENABLE_CHIP_SHELL=y - -# Enable HKDF in mbedtls -CONFIG_MBEDTLS_HKDF_C=y diff --git a/examples/energy-management-app/esp32/sdkconfig.defaults.esp32h2 b/examples/energy-management-app/esp32/sdkconfig.defaults.esp32h2 index eb280c060b2482..078b7f7243987d 100644 --- a/examples/energy-management-app/esp32/sdkconfig.defaults.esp32h2 +++ b/examples/energy-management-app/esp32/sdkconfig.defaults.esp32h2 @@ -1,29 +1,4 @@ CONFIG_IDF_TARGET="esp32h2" -CONFIG_IDF_TARGET_ESP32H2_BETA_VERSION_2=y - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_FLASHMODE_QIO=y -CONFIG_ESPTOOLPY_FLASHFREQ_40M=y -CONFIG_ESPTOOLPY_FLASHFREQ="40m" -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - -# libsodium -CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y - -# Serial Flasher config -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -CONFIG_ESPTOOLPY_FLASHSIZE="4MB" - -# NIMBLE -CONFIG_BT_ENABLED=y -CONFIG_BT_NIMBLE_ENABLED=y -CONFIG_BT_NIMBLE_EXT_ADV=n -CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 -CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=n # Enable OpenThread CONFIG_OPENTHREAD_ENABLED=y @@ -36,45 +11,13 @@ CONFIG_OPENTHREAD_DNS_CLIENT=y # Disable lwip ipv6 autoconfig CONFIG_LWIP_IPV6_AUTOCONFIG=n -# Use a custom partition table -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" - # LwIP config for OpenThread CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 CONFIG_LWIP_MULTICAST_PING=y -# mbedTLS -CONFIG_MBEDTLS_HARDWARE_AES=n -CONFIG_MBEDTLS_HARDWARE_MPI=n -CONFIG_MBEDTLS_HARDWARE_SHA=n -CONFIG_MBEDTLS_HARDWARE_ECC=y -CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN=n -CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY=n -CONFIG_MBEDTLS_CMAC_C=y -CONFIG_MBEDTLS_SSL_PROTO_DTLS=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y - -# rtc clk for ble -# CONFIG_ESP32H2_RTC_CLK_SRC_EXT_CRYS=y - # MDNS platform CONFIG_USE_MINIMAL_MDNS=n CONFIG_ENABLE_EXTENDED_DISCOVERY=y -# FreeRTOS should use legacy API -CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y - -# Disable STA and AP for ESP32H2 +# Disable STA for ESP32H2 CONFIG_ENABLE_WIFI_STATION=n -# Enable this to avoid implicit declaration of function 'esp_send_assoc_resp' -CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y - -# Enable OTA Requestor -CONFIG_ENABLE_OTA_REQUESTOR=y - -# Enable chip shell -CONFIG_ENABLE_CHIP_SHELL=y - -# Enable HKDF in mbedtls -CONFIG_MBEDTLS_HKDF_C=y diff --git a/examples/light-switch-app/esp32/sdkconfig.defaults b/examples/light-switch-app/esp32/sdkconfig.defaults index d0e507742a2f64..a5f416889ace49 100644 --- a/examples/light-switch-app/esp32/sdkconfig.defaults +++ b/examples/light-switch-app/esp32/sdkconfig.defaults @@ -18,13 +18,6 @@ # Some useful defaults for the demo app configuration. # -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - #enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y @@ -58,3 +51,9 @@ CONFIG_MBEDTLS_HKDF_C=y # Increase LwIP IPv6 address number CONFIG_LWIP_IPV6_NUM_ADDRESSES=6 + +# Move functions from IRAM to flash +CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y + +# Enable OTA Requestor +CONFIG_ENABLE_OTA_REQUESTOR=y diff --git a/examples/light-switch-app/esp32/sdkconfig.defaults.esp32c3 b/examples/light-switch-app/esp32/sdkconfig.defaults.esp32c3 index 4db6e947e506ba..62c2cb2fd57f70 100644 --- a/examples/light-switch-app/esp32/sdkconfig.defaults.esp32c3 +++ b/examples/light-switch-app/esp32/sdkconfig.defaults.esp32c3 @@ -1,35 +1 @@ CONFIG_IDF_TARGET="esp32c3" -CONFIG_IDF_TARGET_ESP32C3=y -CONFIG_DEVICE_TYPE_ESP32_C3_DEVKITM=y - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - -#enable BT -CONFIG_BT_ENABLED=y -CONFIG_BT_NIMBLE_ENABLED=y - -#enable lwip ipv6 autoconfig -CONFIG_LWIP_IPV6_AUTOCONFIG=y - -# Use a custom partition table -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" - -#enable lwIP route hooks -CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y -CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y - -# Serial Flasher config -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -CONFIG_ESPTOOLPY_FLASHSIZE="4MB" - -# Enable HKDF in mbedtls -CONFIG_MBEDTLS_HKDF_C=y - -# Move functions from IRAM to flash -CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y diff --git a/examples/lighting-app/esp32/sdkconfig.defaults b/examples/lighting-app/esp32/sdkconfig.defaults index a8833c13a1a23b..bd9f9235540bbb 100644 --- a/examples/lighting-app/esp32/sdkconfig.defaults +++ b/examples/lighting-app/esp32/sdkconfig.defaults @@ -18,13 +18,6 @@ # Some useful defaults for the demo app configuration. # -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - #enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y @@ -64,3 +57,6 @@ CONFIG_DISABLE_READ_CLIENT=y # Increase LwIP IPv6 address number CONFIG_LWIP_IPV6_NUM_ADDRESSES=6 + +# Enable OTA Requestor +CONFIG_ENABLE_OTA_REQUESTOR=y diff --git a/examples/lighting-app/esp32/sdkconfig.defaults.esp32c6 b/examples/lighting-app/esp32/sdkconfig.defaults.esp32c6 index c8617158acb9c0..5844e52c9d3173 100644 --- a/examples/lighting-app/esp32/sdkconfig.defaults.esp32c6 +++ b/examples/lighting-app/esp32/sdkconfig.defaults.esp32c6 @@ -1,70 +1 @@ CONFIG_IDF_TARGET="esp32c6" - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_FLASHMODE_QIO=y -CONFIG_ESPTOOLPY_FLASHFREQ_40M=y -CONFIG_ESPTOOLPY_FLASHFREQ="40m" -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - -# libsodium -CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y - - -# NIMBLE -CONFIG_BT_ENABLED=y -CONFIG_BT_NIMBLE_ENABLED=y -CONFIG_BT_NIMBLE_EXT_ADV=n -CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 -CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=y - -# Disable OpenThread -CONFIG_OPENTHREAD_ENABLED=n - -# Disable lwip ipv6 autoconfig -CONFIG_LWIP_IPV6_AUTOCONFIG=y - -# Use a custom partition table -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" - -# LwIP config for OpenThread -CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 -CONFIG_LWIP_MULTICAST_PING=y - -# mbedTLS -CONFIG_MBEDTLS_HARDWARE_AES=n -CONFIG_MBEDTLS_HARDWARE_MPI=n -CONFIG_MBEDTLS_HARDWARE_SHA=n -CONFIG_MBEDTLS_HARDWARE_ECC=y -CONFIG_MBEDTLS_CMAC_C=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y -CONFIG_MBEDTLS_ECJPAKE_C=y - -# MDNS platform -CONFIG_USE_MINIMAL_MDNS=y -CONFIG_ENABLE_EXTENDED_DISCOVERY=y - -# FreeRTOS should use legacy API -CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y - -# Wi-Fi Settings -CONFIG_ENABLE_WIFI_STATION=y -# Enable this to avoid implicit declaration of function 'esp_send_assoc_resp' -CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y - -# Enable OTA Requestor -CONFIG_ENABLE_OTA_REQUESTOR=y - -# Enable chip shell -CONFIG_ENABLE_CHIP_SHELL=y - -# Enable HKDF in mbedtls -CONFIG_MBEDTLS_HKDF_C=y - -# Serial Flasher config -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -CONFIG_ESPTOOLPY_FLASHSIZE="4MB" diff --git a/examples/lighting-app/esp32/sdkconfig.defaults.esp32h2 b/examples/lighting-app/esp32/sdkconfig.defaults.esp32h2 index eb280c060b2482..078b7f7243987d 100644 --- a/examples/lighting-app/esp32/sdkconfig.defaults.esp32h2 +++ b/examples/lighting-app/esp32/sdkconfig.defaults.esp32h2 @@ -1,29 +1,4 @@ CONFIG_IDF_TARGET="esp32h2" -CONFIG_IDF_TARGET_ESP32H2_BETA_VERSION_2=y - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_FLASHMODE_QIO=y -CONFIG_ESPTOOLPY_FLASHFREQ_40M=y -CONFIG_ESPTOOLPY_FLASHFREQ="40m" -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - -# libsodium -CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y - -# Serial Flasher config -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -CONFIG_ESPTOOLPY_FLASHSIZE="4MB" - -# NIMBLE -CONFIG_BT_ENABLED=y -CONFIG_BT_NIMBLE_ENABLED=y -CONFIG_BT_NIMBLE_EXT_ADV=n -CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 -CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=n # Enable OpenThread CONFIG_OPENTHREAD_ENABLED=y @@ -36,45 +11,13 @@ CONFIG_OPENTHREAD_DNS_CLIENT=y # Disable lwip ipv6 autoconfig CONFIG_LWIP_IPV6_AUTOCONFIG=n -# Use a custom partition table -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" - # LwIP config for OpenThread CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 CONFIG_LWIP_MULTICAST_PING=y -# mbedTLS -CONFIG_MBEDTLS_HARDWARE_AES=n -CONFIG_MBEDTLS_HARDWARE_MPI=n -CONFIG_MBEDTLS_HARDWARE_SHA=n -CONFIG_MBEDTLS_HARDWARE_ECC=y -CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN=n -CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY=n -CONFIG_MBEDTLS_CMAC_C=y -CONFIG_MBEDTLS_SSL_PROTO_DTLS=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y - -# rtc clk for ble -# CONFIG_ESP32H2_RTC_CLK_SRC_EXT_CRYS=y - # MDNS platform CONFIG_USE_MINIMAL_MDNS=n CONFIG_ENABLE_EXTENDED_DISCOVERY=y -# FreeRTOS should use legacy API -CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y - -# Disable STA and AP for ESP32H2 +# Disable STA for ESP32H2 CONFIG_ENABLE_WIFI_STATION=n -# Enable this to avoid implicit declaration of function 'esp_send_assoc_resp' -CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y - -# Enable OTA Requestor -CONFIG_ENABLE_OTA_REQUESTOR=y - -# Enable chip shell -CONFIG_ENABLE_CHIP_SHELL=y - -# Enable HKDF in mbedtls -CONFIG_MBEDTLS_HKDF_C=y diff --git a/examples/lighting-app/esp32/sdkconfig.defaults.esp32p4 b/examples/lighting-app/esp32/sdkconfig.defaults.esp32p4 index 3211b306b2be99..5a5709da53ec84 100644 --- a/examples/lighting-app/esp32/sdkconfig.defaults.esp32p4 +++ b/examples/lighting-app/esp32/sdkconfig.defaults.esp32p4 @@ -1,35 +1,12 @@ CONFIG_IDF_TARGET="esp32p4" -# Flash size and partition -CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" - # Enable BLE Host but use remote controller -CONFIG_BT_ENABLED=y -CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_TRANSPORT_UART=n CONFIG_ESP_ENABLE_BT=y # Increase main task stack size CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096 -# Disable Wi-Fi Soft AP -CONFIG_ESP_WIFI_SOFTAP_SUPPORT=n - -# LwIP -CONFIG_LWIP_IPV6_AUTOCONFIG=y -CONFIG_LWIP_IPV6_NUM_ADDRESSES=6 - -# mbedtls -CONFIG_MBEDTLS_HKDF_C=y - -# Matter shell -CONFIG_ENABLE_CHIP_SHELL=y - -# OTA requestor -CONFIG_ENABLE_OTA_REQUESTOR=y - # Do not deinit BLE after commissioning CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=n diff --git a/examples/lit-icd-app/esp32/sdkconfig.defaults b/examples/lit-icd-app/esp32/sdkconfig.defaults index 4ac165c475a260..b71231e65dc4b3 100644 --- a/examples/lit-icd-app/esp32/sdkconfig.defaults +++ b/examples/lit-icd-app/esp32/sdkconfig.defaults @@ -1,5 +1,3 @@ -# Monitoring baud and flash size -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y # Enable BT diff --git a/examples/lock-app/esp32/sdkconfig.defaults b/examples/lock-app/esp32/sdkconfig.defaults index 4755d2e29635a8..570699b7dad99a 100644 --- a/examples/lock-app/esp32/sdkconfig.defaults +++ b/examples/lock-app/esp32/sdkconfig.defaults @@ -19,13 +19,6 @@ # Some useful defaults for the demo app configuration. # -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - #enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y diff --git a/examples/lock-app/esp32/sdkconfig.defaults.esp32c6 b/examples/lock-app/esp32/sdkconfig.defaults.esp32c6 index a36808e3a4bdc0..5844e52c9d3173 100644 --- a/examples/lock-app/esp32/sdkconfig.defaults.esp32c6 +++ b/examples/lock-app/esp32/sdkconfig.defaults.esp32c6 @@ -1,59 +1 @@ CONFIG_IDF_TARGET="esp32c6" - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_FLASHMODE_QIO=y -CONFIG_ESPTOOLPY_FLASHFREQ_40M=y -CONFIG_ESPTOOLPY_FLASHFREQ="40m" -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - -# libsodium -CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y - -# NIMBLE -CONFIG_BT_ENABLED=y -CONFIG_BT_NIMBLE_ENABLED=y -CONFIG_BT_NIMBLE_EXT_ADV=n -CONFIG_BT_NIMBLE_HCI_EVT_BUF_SIZE=70 -CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=y - -# Disable OpenThread -CONFIG_OPENTHREAD_ENABLED=n - -# Disable lwip ipv6 autoconfig -CONFIG_LWIP_IPV6_AUTOCONFIG=y - -# Use a custom partition table -CONFIG_PARTITION_TABLE_CUSTOM=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" - -# LwIP config for OpenThread -CONFIG_LWIP_IPV6_NUM_ADDRESSES=8 -CONFIG_LWIP_MULTICAST_PING=y - -# mbedTLS -CONFIG_MBEDTLS_HARDWARE_AES=n -CONFIG_MBEDTLS_HARDWARE_MPI=n -CONFIG_MBEDTLS_HARDWARE_SHA=n -CONFIG_MBEDTLS_HARDWARE_ECC=y -CONFIG_MBEDTLS_CMAC_C=y -CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y -CONFIG_MBEDTLS_ECJPAKE_C=y - -# MDNS platform -CONFIG_USE_MINIMAL_MDNS=y -CONFIG_ENABLE_EXTENDED_DISCOVERY=y - -# FreeRTOS should use legacy API -CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITY=y - -# Wi-Fi Settings -CONFIG_ENABLE_WIFI_STATION=y -# Enable this to avoid implicit declaration of function 'esp_send_assoc_resp' -CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y - -# Enable HKDF in mbedtls -CONFIG_MBEDTLS_HKDF_C=y diff --git a/examples/ota-provider-app/esp32/sdkconfig.defaults b/examples/ota-provider-app/esp32/sdkconfig.defaults index 6a06f08a0d51fb..b9bdeb01c335ae 100644 --- a/examples/ota-provider-app/esp32/sdkconfig.defaults +++ b/examples/ota-provider-app/esp32/sdkconfig.defaults @@ -19,14 +19,6 @@ # Some useful defaults for the demo app configuration. # - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - #enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y diff --git a/examples/ota-requestor-app/esp32/sdkconfig.defaults b/examples/ota-requestor-app/esp32/sdkconfig.defaults index b4629c26d79412..2b56f64e4e4fc3 100644 --- a/examples/ota-requestor-app/esp32/sdkconfig.defaults +++ b/examples/ota-requestor-app/esp32/sdkconfig.defaults @@ -19,14 +19,6 @@ # Some useful defaults for the demo app configuration. # - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - #enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y diff --git a/examples/persistent-storage/esp32/sdkconfig.defaults b/examples/persistent-storage/esp32/sdkconfig.defaults index 45488e615dece7..68318243ef2fad 100644 --- a/examples/persistent-storage/esp32/sdkconfig.defaults +++ b/examples/persistent-storage/esp32/sdkconfig.defaults @@ -15,13 +15,6 @@ # limitations under the License. # -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - # Use a custom partition table CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" diff --git a/examples/pigweed-app/esp32/sdkconfig.defaults b/examples/pigweed-app/esp32/sdkconfig.defaults index 6090ca73d6c3f7..2991651fda8a6c 100644 --- a/examples/pigweed-app/esp32/sdkconfig.defaults +++ b/examples/pigweed-app/esp32/sdkconfig.defaults @@ -19,14 +19,6 @@ # Some useful defaults for the demo app configuration. # - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - #enable lwip ipv6 autoconfig CONFIG_LWIP_IPV6_AUTOCONFIG=y diff --git a/examples/shell/esp32/sdkconfig.defaults b/examples/shell/esp32/sdkconfig.defaults index efd5d235a1cf54..e6802e45906318 100644 --- a/examples/shell/esp32/sdkconfig.defaults +++ b/examples/shell/esp32/sdkconfig.defaults @@ -15,14 +15,6 @@ # limitations under the License. # - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - #enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y diff --git a/examples/temperature-measurement-app/esp32/sdkconfig.defaults b/examples/temperature-measurement-app/esp32/sdkconfig.defaults index 3dcab272b297db..9c6a93e1d0dbbc 100644 --- a/examples/temperature-measurement-app/esp32/sdkconfig.defaults +++ b/examples/temperature-measurement-app/esp32/sdkconfig.defaults @@ -19,14 +19,6 @@ # Some useful defaults for the demo app configuration. # - -# Default to 921600 baud when flashing and monitoring device -CONFIG_ESPTOOLPY_BAUD_921600B=y -CONFIG_ESPTOOLPY_BAUD=921600 -CONFIG_ESPTOOLPY_COMPRESSED=y -CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y -CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 - #enable BT CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y diff --git a/scripts/build/builders/esp32.py b/scripts/build/builders/esp32.py index 02f7e25e55a693..868bf0ad19da7d 100644 --- a/scripts/build/builders/esp32.py +++ b/scripts/build/builders/esp32.py @@ -124,7 +124,7 @@ def DefaultsFileName(board: Esp32Board, app: Esp32App, enable_rpcs: bool): return 'sdkconfig.defaults' rpc = "_rpc" if enable_rpcs else "" - if board == Esp32Board.DevKitC: + if board == Esp32Board.DevKitC or board == Esp32Board.C3DevKit: return 'sdkconfig{}.defaults'.format(rpc) elif board == Esp32Board.M5Stack: # a subset of apps have m5stack specific configurations. However others @@ -139,8 +139,6 @@ def DefaultsFileName(board: Esp32Board, app: Esp32App, enable_rpcs: bool): return 'sdkconfig_m5stack{}.defaults'.format(rpc) else: return 'sdkconfig{}.defaults'.format(rpc) - elif board == Esp32Board.C3DevKit: - return 'sdkconfig{}.defaults.esp32c3'.format(rpc) else: raise Exception('Unknown board type') @@ -173,6 +171,20 @@ def _IdfEnvExecute(self, cmd, title=None): ['bash', '-c', 'source $IDF_PATH/export.sh; source scripts/activate.sh; %s' % cmd], title=title) + @property + def TargetName(self): + if self.board == Esp32Board.C3DevKit: + return 'esp32c3' + else: + return 'esp32' + + @property + def TargetFileName(self) -> Optional[str]: + if self.board == Esp32Board.C3DevKit: + return 'sdkconfig.defaults.esp32c3' + else: + return None + @property def ExamplePath(self): return os.path.join(self.app.ExamplePath, 'esp32') @@ -195,6 +207,11 @@ def generate(self): self._Execute( ['rm', '-f', os.path.join(self.ExamplePath, 'sdkconfig')]) + if self.TargetFileName is not None: + target_defaults = os.path.join(self.ExamplePath, self.TargetFileName) + if os.path.exists(target_defaults): + self._Execute(['cp', target_defaults, os.path.join(self.output_dir, self.TargetFileName)]) + if not self.enable_ipv4: self._Execute( ['bash', '-c', 'echo -e "\\nCONFIG_DISABLE_IPV4=y\\n" >>%s' % shlex.quote(defaults_out)]) @@ -221,8 +238,9 @@ def generate(self): cmake_args = " ".join(cmake_args) defaults = shlex.quote(defaults_out) + target = shlex.quote(self.TargetName) - cmd = f"\nexport SDKCONFIG_DEFAULTS={defaults}\nidf.py {cmake_args} reconfigure" + cmd = f"\nexport SDKCONFIG_DEFAULTS={defaults}\nidf.py {cmake_args} -DIDF_TARGET={target} reconfigure" # This will do a 'cmake reconfigure' which will create ninja files without rebuilding self._IdfEnvExecute(cmd) diff --git a/scripts/build/testdata/dry_run_esp32-devkitc-light-rpc.txt b/scripts/build/testdata/dry_run_esp32-devkitc-light-rpc.txt index cb5e3df310e36d..844a68132577c1 100644 --- a/scripts/build/testdata/dry_run_esp32-devkitc-light-rpc.txt +++ b/scripts/build/testdata/dry_run_esp32-devkitc-light-rpc.txt @@ -12,7 +12,7 @@ bash -c 'echo -e "\nCONFIG_ESP_INSIGHTS_ENABLED=n\nCONFIG_ENABLE_ESP_INSIGHTS_TR bash -c 'source $IDF_PATH/export.sh; source scripts/activate.sh; export SDKCONFIG_DEFAULTS={out}/esp32-devkitc-light-rpc/sdkconfig.defaults -idf.py -C examples/lighting-app/esp32 -B {out}/esp32-devkitc-light-rpc reconfigure' +idf.py -C examples/lighting-app/esp32 -B {out}/esp32-devkitc-light-rpc -DIDF_TARGET=esp32 reconfigure' rm -f examples/lighting-app/esp32/sdkconfig From abda28c3945d68abce12d2b02d465c7a74824e98 Mon Sep 17 00:00:00 2001 From: C Freeman Date: Thu, 23 Jan 2025 09:27:22 -0500 Subject: [PATCH 11/40] DM XML parsing: Fix type annotations (#36914) Takes mypy errors down from 79 to 27. Nearly all remaining are related to Enum - mypy has support for Enum functions, but it seems like the derived classes are messing it up. Can be addressed in a followup - this is still better. The goal here is mostly to tighten up the type annotations and move int -> uint for ids where possible, such that the spec parsing is providing data with a stronger guarantee. Testing: Tested by TestSpecParsing.py and TestSpecParsingDeviceTypes.py Also used by tests run in CI (including above) --- .../chip/testing/spec_parsing.py | 171 ++++++++++-------- 1 file changed, 96 insertions(+), 75 deletions(-) diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/spec_parsing.py b/src/python_testing/matter_testing_infrastructure/chip/testing/spec_parsing.py index 8160dc7ba99f62..7bd247746a07e5 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/spec_parsing.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/spec_parsing.py @@ -33,7 +33,7 @@ parse_callable_from_xml, parse_device_type_callable_from_xml) from chip.testing.global_attribute_ids import GlobalAttributeIds from chip.testing.matter_testing import (AttributePathLocation, ClusterPathLocation, CommandPathLocation, DeviceTypePathLocation, - EventPathLocation, FeaturePathLocation, ProblemNotice, ProblemSeverity) + EventPathLocation, FeaturePathLocation, ProblemLocation, ProblemNotice, ProblemSeverity) from chip.tlv import uint _PRIVILEGE_STR = { @@ -53,18 +53,22 @@ class SpecParsingException(Exception): pass +# passing in feature map, attribute list, command list +ConformanceCallable = Callable[[uint, list[uint], list[uint]], ConformanceDecision] + + @dataclass class XmlFeature: code: str name: str - conformance: Callable[[uint], ConformanceDecision] + conformance: ConformanceCallable @dataclass class XmlAttribute: name: str datatype: str - conformance: Callable[[uint], ConformanceDecision] + conformance: ConformanceCallable read_access: Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum write_access: Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum write_optional: bool @@ -84,20 +88,20 @@ def __str__(self): class XmlCommand: id: int name: str - conformance: Callable[[uint], ConformanceDecision] + conformance: ConformanceCallable @dataclass class XmlEvent: name: str - conformance: Callable[[uint], ConformanceDecision] + conformance: ConformanceCallable @dataclass class XmlCluster: name: str revision: int - derived: str + derived: Optional[str] feature_map: dict[str, uint] attribute_map: dict[str, uint] command_map: dict[str, uint] @@ -122,7 +126,7 @@ class ClusterSide(Enum): class XmlDeviceTypeClusterRequirements: name: str side: ClusterSide - conformance: Callable[[uint, list[uint], list[uint]], ConformanceDecision] + conformance: ConformanceCallable # TODO: add element requirements def __str__(self): @@ -177,21 +181,22 @@ class CommandType(Enum): DEVICE_TYPE_NAME_FIXES = {0x010b: 'Dimmable Plug-In Unit', 0x010a: 'On/Off Plug-in Unit'} -def get_location_from_element(element: ElementTree.Element, cluster_id: int): +def get_location_from_element(element: ElementTree.Element, cluster_id: Optional[int]) -> ProblemLocation: + if cluster_id is None: + cluster_id = 0 if element.tag == 'feature': - location = FeaturePathLocation(endpoint_id=0, cluster_id=cluster_id, feature_code=element.attrib['code']) + return FeaturePathLocation(endpoint_id=0, cluster_id=cluster_id, feature_code=element.attrib['code']) elif element.tag == 'command': - location = CommandPathLocation(endpoint_id=0, cluster_id=cluster_id, command_id=int(element.attrib['id'], 0)) + return CommandPathLocation(endpoint_id=0, cluster_id=cluster_id, command_id=int(element.attrib['id'], 0)) elif element.tag == 'attribute': - location = AttributePathLocation(endpoint_id=0, cluster_id=cluster_id, attribute_id=int(element.attrib['id'], 0)) + return AttributePathLocation(endpoint_id=0, cluster_id=cluster_id, attribute_id=int(element.attrib['id'], 0)) elif element.tag == 'event': - location = EventPathLocation(endpoint_id=0, cluster_id=cluster_id, event_id=int(element.attrib['id'], 0)) + return EventPathLocation(endpoint_id=0, cluster_id=cluster_id, event_id=int(element.attrib['id'], 0)) else: - location = ClusterPathLocation(endpoint_id=0, cluster_id=cluster_id) - return location + return ClusterPathLocation(endpoint_id=0, cluster_id=cluster_id) -def get_conformance(element: ElementTree.Element, cluster_id: int) -> tuple[ElementTree.Element, typing.Optional[ProblemNotice]]: +def get_conformance(element: ElementTree.Element, cluster_id: Optional[uint]) -> tuple[ElementTree.Element, typing.Optional[ProblemNotice]]: for sub in element: if sub.tag in TOP_LEVEL_CONFORMANCE_TAGS: return sub, None @@ -201,8 +206,13 @@ def get_conformance(element: ElementTree.Element, cluster_id: int) -> tuple[Elem return ElementTree.Element(OPTIONAL_CONFORM), problem +# Tuple of the root element, the conformance xml element within the root and the optional access element within the root +XmlElementDescriptor = tuple[ElementTree.Element, ElementTree.Element, Optional[ElementTree.Element]] + + class ClusterParser: - def __init__(self, cluster, cluster_id, name): + # Cluster ID is optional to support base clusters that have no ID of their own. + def __init__(self, cluster: ElementTree.Element, cluster_id: Optional[uint], name: str): self._problems: list[ProblemNotice] = [] self._cluster = cluster self._cluster_id = cluster_id @@ -222,6 +232,7 @@ def __init__(self, cluster, cluster_id, name): if list(id.iter('provisionalConform')): self._is_provisional = True + self._pics: Optional[str] = None try: classification = next(cluster.iter('classification')) self._pics = classification.attrib['picsCode'] @@ -250,7 +261,7 @@ def get_access(self, element: ElementTree.Element) -> Optional[ElementTree.Eleme return sub return None - def get_all_type(self, type_container: str, type_name: str, key_name: str) -> list[tuple[ElementTree.Element, ElementTree.Element, ElementTree.Element]]: + def get_all_type(self, type_container: str, type_name: str, key_name: str) -> list[XmlElementDescriptor]: ret = [] container_tags = self._cluster.iter(type_container) for container in container_tags: @@ -266,54 +277,56 @@ def get_all_type(self, type_container: str, type_name: str, key_name: str) -> li ret.append((element, conformance, access)) return ret - def get_all_feature_elements(self) -> list[tuple[ElementTree.Element, ElementTree.Element]]: + def get_all_feature_elements(self) -> list[XmlElementDescriptor]: ''' Returns a list of features and their conformances''' return self.get_all_type('features', 'feature', 'code') - def get_all_attribute_elements(self) -> list[tuple[ElementTree.Element, ElementTree.Element]]: + def get_all_attribute_elements(self) -> list[XmlElementDescriptor]: ''' Returns a list of attributes and their conformances''' return self.get_all_type('attributes', 'attribute', 'id') - def get_all_command_elements(self) -> list[tuple[ElementTree.Element, ElementTree.Element]]: + def get_all_command_elements(self) -> list[XmlElementDescriptor]: ''' Returns a list of commands and their conformances ''' return self.get_all_type('commands', 'command', 'id') - def get_all_event_elements(self) -> list[tuple[ElementTree.Element, ElementTree.Element]]: + def get_all_event_elements(self) -> list[XmlElementDescriptor]: ''' Returns a list of events and their conformances''' return self.get_all_type('events', 'event', 'id') def create_feature_map(self) -> dict[str, uint]: features = {} for element, _, _ in self.feature_elements: - features[element.attrib['code']] = 1 << int(element.attrib['bit'], 0) + features[element.attrib['code']] = uint(1 << int(element.attrib['bit'], 0)) return features def create_attribute_map(self) -> dict[str, uint]: attributes = {} for element, conformance, _ in self.attribute_elements: - attributes[element.attrib['name']] = int(element.attrib['id'], 0) + attributes[element.attrib['name']] = uint(int(element.attrib['id'], 0)) return attributes def create_command_map(self) -> dict[str, uint]: commands = {} for element, _, _ in self.command_elements: - commands[element.attrib['name']] = int(element.attrib['id'], 0) + commands[element.attrib['name']] = uint(int(element.attrib['id'], 0)) return commands - def parse_conformance(self, conformance_xml: ElementTree.Element) -> Callable: + def parse_conformance(self, conformance_xml: ElementTree.Element) -> Optional[ConformanceCallable]: try: return parse_callable_from_xml(conformance_xml, self.params) except ConformanceException as ex: # Just point to the general cluster, because something is mismatched, but it's not clear what - location = ClusterPathLocation(endpoint_id=0, cluster_id=self._cluster_id) + location = ClusterPathLocation(endpoint_id=0, cluster_id=self._cluster_id if self._cluster_id is not None else 0) self._problems.append(ProblemNotice(test_name='Spec XML parsing', location=location, severity=ProblemSeverity.WARNING, problem=str(ex))) return None - def parse_write_optional(self, element_xml: ElementTree.Element, access_xml: ElementTree.Element) -> bool: + def parse_write_optional(self, element_xml: ElementTree.Element, access_xml: Optional[ElementTree.Element]) -> bool: + if access_xml is None: + return False return access_xml.attrib['write'] == 'optional' - def parse_access(self, element_xml: ElementTree.Element, access_xml: ElementTree.Element, conformance: Callable) -> tuple[Optional[Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum], Optional[Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum], Optional[Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum]]: + def parse_access(self, element_xml: ElementTree.Element, access_xml: Optional[ElementTree.Element], conformance: Callable) -> tuple[Optional[Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum], Optional[Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum], Optional[Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum]]: ''' Returns a tuple of access types for read / write / invoke''' def str_to_access_type(privilege_str: str) -> Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum: if privilege_str == 'view': @@ -361,7 +374,7 @@ def str_to_access_type(privilege_str: str) -> Clusters.AccessControl.Enums.Acces def parse_features(self) -> dict[uint, XmlFeature]: features = {} for element, conformance_xml, _ in self.feature_elements: - mask = 1 << int(element.attrib['bit'], 0) + mask = uint(1 << int(element.attrib['bit'], 0)) conformance = self.parse_conformance(conformance_xml) if conformance is None: continue @@ -370,9 +383,9 @@ def parse_features(self) -> dict[uint, XmlFeature]: return features def parse_attributes(self) -> dict[uint, XmlAttribute]: - attributes = {} + attributes: dict[uint, XmlAttribute] = {} for element, conformance_xml, access_xml in self.attribute_elements: - code = int(element.attrib['id'], 0) + code = uint(int(element.attrib['id'], 0)) # Some deprecated attributes don't have their types included, for now, lets just fallback to UNKNOWN try: datatype = element.attrib['type'] @@ -394,7 +407,7 @@ def parse_attributes(self) -> dict[uint, XmlAttribute]: # Add in the global attributes for the base class for id in GlobalAttributeIds: # TODO: Add data type here. Right now it's unused. We should parse this from the spec. - attributes[id] = XmlAttribute(name=id.to_name(), datatype="", conformance=mandatory( + attributes[uint(id)] = XmlAttribute(name=id.to_name(), datatype="", conformance=mandatory( ), read_access=Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum.kView, write_access=Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum.kUnknownEnumValue, write_optional=False) return attributes @@ -419,27 +432,28 @@ def parse_unknown_commands(self) -> list[XmlCommand]: continue code = int(element.attrib['id'], 0) conformance = self.parse_conformance(conformance_xml) - commands.append(XmlCommand(id=code, name=element.attrib['name'], conformance=conformance)) + if conformance is not None: + commands.append(XmlCommand(id=code, name=element.attrib['name'], conformance=conformance)) return commands def parse_commands(self, command_type: CommandType) -> dict[uint, XmlCommand]: - commands = {} + commands: dict[uint, XmlCommand] = {} for element, conformance_xml, access_xml in self.command_elements: if self.get_command_type(element) != command_type: continue - code = int(element.attrib['id'], 0) + code = uint(int(element.attrib['id'], 0)) conformance = self.parse_conformance(conformance_xml) if conformance is None: continue if code in commands: conformance = or_operation([conformance, commands[code].conformance]) - commands[code] = XmlCommand(id=code, name=element.attrib['name'], conformance=conformance) + commands[uint(code)] = XmlCommand(id=code, name=element.attrib['name'], conformance=conformance) return commands - def parse_events(self) -> dict[uint, XmlAttribute]: - events = {} + def parse_events(self) -> dict[uint, XmlEvent]: + events: dict[uint, XmlEvent] = {} for element, conformance_xml, access_xml in self.event_elements: - code = int(element.attrib['id'], 0) + code = uint(int(element.attrib['id'], 0)) conformance = self.parse_conformance(conformance_xml) if conformance is None: continue @@ -467,7 +481,7 @@ def get_problems(self) -> list[ProblemNotice]: return self._problems -def add_cluster_data_from_xml(xml: ElementTree.Element, clusters: dict[int, XmlCluster], pure_base_clusters: dict[str, XmlCluster], ids_by_name: dict[str, int], problems: list[ProblemNotice]) -> None: +def add_cluster_data_from_xml(xml: ElementTree.Element, clusters: dict[uint, XmlCluster], pure_base_clusters: dict[str, XmlCluster], ids_by_name: dict[str, uint], problems: list[ProblemNotice]) -> None: ''' Adds cluster data to the supplied dicts as appropriate xml: XML element read from from the XML cluster file @@ -482,10 +496,16 @@ def add_cluster_data_from_xml(xml: ElementTree.Element, clusters: dict[int, XmlC ids = c.iter('clusterId') for id in ids: name = id.get('name') - cluster_id = id.get('id') - if cluster_id: - cluster_id = int(id.get('id'), 0) - ids_by_name[name] = cluster_id + cluster_id_str = id.get('id') + cluster_id: Optional[uint] = None + if cluster_id_str: + cluster_id = uint(int(cluster_id_str, 0)) + + if name is None: + location = ClusterPathLocation(endpoint_id=0, cluster_id=0 if cluster_id is None else cluster_id) + problems.append(ProblemNotice(test_name="Spec XML parsing", location=location, + severity=ProblemSeverity.WARNING, problem=f"Cluster with no name {cluster}")) + continue parser = ClusterParser(c, cluster_id, name) new = parser.create_cluster() @@ -493,6 +513,7 @@ def add_cluster_data_from_xml(xml: ElementTree.Element, clusters: dict[int, XmlC if cluster_id: clusters[cluster_id] = new + ids_by_name[name] = cluster_id else: # Fully derived clusters have no id, but also shouldn't appear on a device. # We do need to keep them, though, because we need to update the derived @@ -501,7 +522,7 @@ def add_cluster_data_from_xml(xml: ElementTree.Element, clusters: dict[int, XmlC pure_base_clusters[name] = new -def check_clusters_for_unknown_commands(clusters: dict[int, XmlCluster], problems: list[ProblemNotice]): +def check_clusters_for_unknown_commands(clusters: dict[uint, XmlCluster], problems: list[ProblemNotice]): for id, cluster in clusters.items(): for cmd in cluster.unknown_commands: problems.append(ProblemNotice(test_name="Spec XML parsing", location=CommandPathLocation( @@ -553,7 +574,7 @@ def get_data_model_directory(data_model_directory: Union[PrebuiltDataModelDirect 'data_model').joinpath(data_model_directory.dirname).joinpath(data_model_level.dirname) -def build_xml_clusters(data_model_directory: Union[PrebuiltDataModelDirectory, Traversable] = PrebuiltDataModelDirectory.k1_4) -> typing.Tuple[dict[int, dict], list]: +def build_xml_clusters(data_model_directory: Union[PrebuiltDataModelDirectory, Traversable] = PrebuiltDataModelDirectory.k1_4) -> typing.Tuple[dict[uint, XmlCluster], list[ProblemNotice]]: """ Build XML clusters from the specified data model directory. This function supports both pre-built locations and full paths. @@ -563,9 +584,9 @@ def build_xml_clusters(data_model_directory: Union[PrebuiltDataModelDirectory, T with all XML files in it) """ - clusters: dict[int, XmlCluster] = {} + clusters: dict[uint, XmlCluster] = {} pure_base_clusters: dict[str, XmlCluster] = {} - ids_by_name: dict[str, int] = {} + ids_by_name: dict[str, uint] = {} problems: list[ProblemNotice] = [] top = get_data_model_directory(data_model_directory, DataModelLevel.kCluster) @@ -601,13 +622,13 @@ def remove_problem(location: typing.Union[CommandPathLocation, FeaturePathLocati nonlocal problems problems = [p for p in problems if p.location != location] - descriptor_id = Clusters.Descriptor.id + descriptor_id = uint(Clusters.Descriptor.id) code = 'TAGLIST' mask = clusters[descriptor_id].feature_map[code] clusters[descriptor_id].features[mask].conformance = optional() remove_problem(FeaturePathLocation(endpoint_id=0, cluster_id=descriptor_id, feature_code=code)) - action_id = Clusters.Actions.id + action_id = uint(Clusters.Actions.id) for c in Clusters.ClusterObjects.ALL_ACCEPTED_COMMANDS[action_id]: clusters[action_id].accepted_commands[c].conformance = optional() remove_problem(CommandPathLocation(endpoint_id=0, cluster_id=action_id, command_id=c)) @@ -619,7 +640,7 @@ def remove_problem(location: typing.Union[CommandPathLocation, FeaturePathLocati # to implement either arithmetic conformance handling (once spec changes land here) or specific test # https://github.com/CHIP-Specifications/connectedhomeip-spec/pull/7808 for spec changes. # see 3.2.8. Defined Primaries Information Attribute Set, affects Primary<#>X/Y/Intensity attributes. - cc_id = Clusters.ColorControl.id + cc_id = uint(Clusters.ColorControl.id) cc_attr = Clusters.ColorControl.Attributes affected_attributes = [cc_attr.Primary1X, cc_attr.Primary1Y, @@ -645,44 +666,45 @@ def remove_problem(location: typing.Union[CommandPathLocation, FeaturePathLocati # Workaround for temp control cluster - this is parsed incorrectly in the DM XML and is missing all its attributes # Remove this workaround when https://github.com/csa-data-model/projects/issues/330 is fixed - temp_control_id = Clusters.TemperatureControl.id + temp_control_id = uint(Clusters.TemperatureControl.id) if temp_control_id in clusters and not clusters[temp_control_id].attributes: view = Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum.kView none = Clusters.AccessControl.Enums.AccessControlEntryPrivilegeEnum.kUnknownEnumValue clusters[temp_control_id].attributes = { - 0x00: XmlAttribute(name='TemperatureSetpoint', datatype='temperature', conformance=feature(0x01, 'TN'), read_access=view, write_access=none, write_optional=False), - 0x01: XmlAttribute(name='MinTemperature', datatype='temperature', conformance=feature(0x01, 'TN'), read_access=view, write_access=none, write_optional=False), - 0x02: XmlAttribute(name='MaxTemperature', datatype='temperature', conformance=feature(0x01, 'TN'), read_access=view, write_access=none, write_optional=False), - 0x03: XmlAttribute(name='Step', datatype='temperature', conformance=feature(0x04, 'STEP'), read_access=view, write_access=none, write_optional=False), - 0x04: XmlAttribute(name='SelectedTemperatureLevel', datatype='uint8', conformance=feature(0x02, 'TL'), read_access=view, write_access=none, write_optional=False), - 0x05: XmlAttribute(name='SupportedTemperatureLevels', datatype='list', conformance=feature(0x02, 'TL'), read_access=view, write_access=none, write_optional=False), + uint(0x00): XmlAttribute(name='TemperatureSetpoint', datatype='temperature', conformance=feature(uint(0x01), 'TN'), read_access=view, write_access=none, write_optional=False), + uint(0x01): XmlAttribute(name='MinTemperature', datatype='temperature', conformance=feature(uint(0x01), 'TN'), read_access=view, write_access=none, write_optional=False), + uint(0x02): XmlAttribute(name='MaxTemperature', datatype='temperature', conformance=feature(uint(0x01), 'TN'), read_access=view, write_access=none, write_optional=False), + uint(0x03): XmlAttribute(name='Step', datatype='temperature', conformance=feature(uint(0x04), 'STEP'), read_access=view, write_access=none, write_optional=False), + uint(0x04): XmlAttribute(name='SelectedTemperatureLevel', datatype='uint8', conformance=feature(uint(0x02), 'TL'), read_access=view, write_access=none, write_optional=False), + uint(0x05): XmlAttribute(name='SupportedTemperatureLevels', datatype='list', conformance=feature(uint(0x02), 'TL'), read_access=view, write_access=none, write_optional=False), } # TODO: Need automated parsing for atomic attributes. - atomic_request_cmd_id = 0xFE - atomic_response_cmd_id = 0xFD + atomic_request_cmd_id = uint(0xFE) + atomic_response_cmd_id = uint(0xFD) atomic_request_name = "Atomic Request" atomic_response_name = "Atomic Response" presets_name = "Presets" schedules_name = "Schedules" - if clusters[Clusters.Thermostat.id].revision >= 8: - presents_id = clusters[Clusters.Thermostat.id].attribute_map[presets_name] - schedules_id = clusters[Clusters.Thermostat.id].attribute_map[schedules_name] + thermostat_id = uint(Clusters.Thermostat.id) + if clusters[thermostat_id].revision >= 8: + presents_id = clusters[thermostat_id].attribute_map[presets_name] + schedules_id = clusters[thermostat_id].attribute_map[schedules_name] conformance = or_operation([conformance_support.attribute(presents_id, presets_name), conformance_support.attribute(schedules_id, schedules_name)]) - clusters[Clusters.Thermostat.id].accepted_commands[atomic_request_cmd_id] = XmlCommand( + clusters[thermostat_id].accepted_commands[atomic_request_cmd_id] = XmlCommand( id=atomic_request_cmd_id, name=atomic_request_name, conformance=conformance) - clusters[Clusters.Thermostat.id].generated_commands[atomic_response_cmd_id] = XmlCommand( + clusters[thermostat_id].generated_commands[atomic_response_cmd_id] = XmlCommand( id=atomic_response_cmd_id, name=atomic_response_name, conformance=conformance) - clusters[Clusters.Thermostat.id].command_map[atomic_request_name] = atomic_request_cmd_id - clusters[Clusters.Thermostat.id].command_map[atomic_response_name] = atomic_response_cmd_id + clusters[thermostat_id].command_map[atomic_request_name] = atomic_request_cmd_id + clusters[thermostat_id].command_map[atomic_response_name] = atomic_response_cmd_id check_clusters_for_unknown_commands(clusters, problems) return clusters, problems -def combine_derived_clusters_with_base(xml_clusters: dict[int, XmlCluster], pure_base_clusters: dict[str, XmlCluster], ids_by_name: dict[str, int], problems: list[ProblemNotice]) -> None: +def combine_derived_clusters_with_base(xml_clusters: dict[uint, XmlCluster], pure_base_clusters: dict[str, XmlCluster], ids_by_name: dict[str, uint], problems: list[ProblemNotice]) -> None: ''' Overrides base elements with the derived cluster values for derived clusters. ''' def combine_attributes(base: dict[uint, XmlAttribute], derived: dict[uint, XmlAttribute], cluster_id: uint, problems: list[ProblemNotice]) -> dict[uint, XmlAttribute]: @@ -734,10 +756,10 @@ def combine_attributes(base: dict[uint, XmlAttribute], derived: dict[uint, XmlAt events.update(c.events) unknown_commands = deepcopy(base.unknown_commands) for cmd in c.unknown_commands: - if cmd.id in accepted_commands.keys() and cmd.name == accepted_commands[cmd.id].name: - accepted_commands[cmd.id].conformance = cmd.conformance - elif cmd.id in generated_commands.keys() and cmd.name == generated_commands[cmd.id].name: - generated_commands[cmd.id].conformance = cmd.conformance + if cmd.id in accepted_commands.keys() and cmd.name == accepted_commands[uint(cmd.id)].name: + accepted_commands[uint(cmd.id)].conformance = cmd.conformance + elif cmd.id in generated_commands.keys() and cmd.name == generated_commands[uint(cmd.id)].name: + generated_commands[uint(cmd.id)].conformance = cmd.conformance else: unknown_commands.append(cmd) provisional = c.is_provisional or base.is_provisional @@ -784,7 +806,6 @@ def parse_single_device_type(root: ElementTree.Element) -> tuple[dict[int, XmlDe except (KeyError, StopIteration): # this is fine for base device type if id == -1: - classification = 'BASE' scope = 'BASE' device_class = 'BASE' else: @@ -797,7 +818,7 @@ def parse_single_device_type(root: ElementTree.Element) -> tuple[dict[int, XmlDe clusters = d.iter('cluster') for c in clusters: try: - cid = int(c.attrib['id'], 0) + cid = uint(int(c.attrib['id'], 0)) conformance_xml, tmp_problem = get_conformance(c, cid) if tmp_problem: problems.append(tmp_problem) @@ -825,7 +846,7 @@ def parse_single_device_type(root: ElementTree.Element) -> tuple[dict[int, XmlDe def build_xml_device_types(data_model_directory: typing.Union[PrebuiltDataModelDirectory, Traversable] = PrebuiltDataModelDirectory.k1_4) -> tuple[dict[int, XmlDeviceType], list[ProblemNotice]]: top = get_data_model_directory(data_model_directory, DataModelLevel.kDeviceType) device_types: dict[int, XmlDeviceType] = {} - problems = [] + problems: list[ProblemNotice] = [] found_xmls = 0 From 48e1edbf0ba4b9da301035366dbd564993aa65d6 Mon Sep 17 00:00:00 2001 From: austina-csa <168131796+austina-csa@users.noreply.github.com> Date: Thu, 23 Jan 2025 06:30:06 -0800 Subject: [PATCH 12/40] Worked on issue 42 (#36961) --- .../suites/certification/Test_TC_IDM_8_1.yaml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/app/tests/suites/certification/Test_TC_IDM_8_1.yaml b/src/app/tests/suites/certification/Test_TC_IDM_8_1.yaml index 7ac77d99517260..596bbe950afec9 100644 --- a/src/app/tests/suites/certification/Test_TC_IDM_8_1.yaml +++ b/src/app/tests/suites/certification/Test_TC_IDM_8_1.yaml @@ -576,19 +576,3 @@ tests: [1660742276.568954][17561:17566] CHIP:DMG: MoveToState ReadClient[0x7f8624024eb0]: Moving to [AwaitingSu] [1660742276.568986][17561:17566] CHIP:EM: Piggybacking Ack for MessageCounter:39674556 on exchange: 26542i disabled: true - - - label: - "RC1 sends Subscribe Request Message to DUT with EventRequests set to - path where an event in the path is fabric-sensitive and the associated - fabric does not match the accessing fabric." - verification: | - Mark this as not testable /NA. Out of Scope for V1.1 - disabled: true - - - label: - "RC1 sends Read Request Message to DUT with EventRequests set to path - where an event in the path is fabric-sensitive and the associated - fabric does not match the accessing fabric." - verification: | - Mark this as not testable /NA. Out of Scope for V1.0 - disabled: true From 04f16889e14d5cacb73a9ecd4b318e035742512e Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Thu, 23 Jan 2025 09:38:43 -0500 Subject: [PATCH 13/40] Update PW-RPC service to use `DataModel::Provider` for writes (#37160) * Avoid PW-RPC assertion error if application is stopped without any RPC connections * Anoter PWRPC crash fix * Implement the write from TLV * Update protos to support string and bytes as separate types for encode/decode * Restyle * make writes actually work * Make write(read.tlv) actually work * Fix typo --- .../pigweed/protos/attributes_service.options | 1 + .../pigweed/protos/attributes_service.proto | 387 +++++++++--------- .../common/pigweed/rpc_services/Attributes.h | 201 ++++++++- examples/platform/linux/system_rpc_server.cc | 22 +- 4 files changed, 393 insertions(+), 218 deletions(-) diff --git a/examples/common/pigweed/protos/attributes_service.options b/examples/common/pigweed/protos/attributes_service.options index 247d0c5404c3e2..aa6b7acb9cb6e0 100644 --- a/examples/common/pigweed/protos/attributes_service.options +++ b/examples/common/pigweed/protos/attributes_service.options @@ -1,3 +1,4 @@ chip.rpc.AttributeData.data_bytes max_size:128 +chip.rpc.AttributeData.data_string max_size:128 chip.rpc.AttributeData.tlv_data max_size:256 diff --git a/examples/common/pigweed/protos/attributes_service.proto b/examples/common/pigweed/protos/attributes_service.proto index ef34448f93b68f..55276f0dadf564 100644 --- a/examples/common/pigweed/protos/attributes_service.proto +++ b/examples/common/pigweed/protos/attributes_service.proto @@ -5,203 +5,203 @@ import 'pw_protobuf_protos/common.proto'; package chip.rpc; enum AttributeType { - ZCL_NO_DATA_ATTRIBUTE_TYPE = 0x00; // No data - ZCL_BOOLEAN_ATTRIBUTE_TYPE = 0x10; // Boolean - ZCL_BITMAP8_ATTRIBUTE_TYPE = 0x18; // 8-bit bitmap - ZCL_BITMAP16_ATTRIBUTE_TYPE = 0x19; // 16-bit bitmap - ZCL_BITMAP32_ATTRIBUTE_TYPE = 0x1B; // 32-bit bitmap - ZCL_BITMAP64_ATTRIBUTE_TYPE = 0x1F; // 64-bit bitmap - ZCL_INT8U_ATTRIBUTE_TYPE = 0x20; // Unsigned 8-bit integer - ZCL_INT16U_ATTRIBUTE_TYPE = 0x21; // Unsigned 16-bit integer - ZCL_INT24U_ATTRIBUTE_TYPE = 0x22; // Unsigned 24-bit integer - ZCL_INT32U_ATTRIBUTE_TYPE = 0x23; // Unsigned 32-bit integer - ZCL_INT40U_ATTRIBUTE_TYPE = 0x24; // Unsigned 40-bit integer - ZCL_INT48U_ATTRIBUTE_TYPE = 0x25; // Unsigned 48-bit integer - ZCL_INT56U_ATTRIBUTE_TYPE = 0x26; // Unsigned 56-bit integer - ZCL_INT64U_ATTRIBUTE_TYPE = 0x27; // Unsigned 64-bit integer - ZCL_INT8S_ATTRIBUTE_TYPE = 0x28; // Signed 8-bit integer - ZCL_INT16S_ATTRIBUTE_TYPE = 0x29; // Signed 16-bit integer - ZCL_INT24S_ATTRIBUTE_TYPE = 0x2A; // Signed 24-bit integer - ZCL_INT32S_ATTRIBUTE_TYPE = 0x2B; // Signed 32-bit integer - ZCL_INT40S_ATTRIBUTE_TYPE = 0x2C; // Signed 40-bit integer - ZCL_INT48S_ATTRIBUTE_TYPE = 0x2D; // Signed 48-bit integer - ZCL_INT56S_ATTRIBUTE_TYPE = 0x2E; // Signed 56-bit integer - ZCL_INT64S_ATTRIBUTE_TYPE = 0x2F; // Signed 64-bit integer - ZCL_ENUM8_ATTRIBUTE_TYPE = 0x30; // 8-bit enumeration - ZCL_ENUM16_ATTRIBUTE_TYPE = 0x31; // 16-bit enumeration - ZCL_SINGLE_ATTRIBUTE_TYPE = 0x39; // Single precision - ZCL_DOUBLE_ATTRIBUTE_TYPE = 0x3A; // Double precision - ZCL_OCTET_STRING_ATTRIBUTE_TYPE = 0x41; // Octet String - ZCL_CHAR_STRING_ATTRIBUTE_TYPE = 0x42; // Character String - ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE = 0x43; // Long Octet String - ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE = 0x44; // Long Character String - ZCL_ARRAY_ATTRIBUTE_TYPE = 0x48; // List - ZCL_STRUCT_ATTRIBUTE_TYPE = 0x4C; // Structure - ZCL_TOD_ATTRIBUTE_TYPE = 0xE0; // Time of day - ZCL_DATE_ATTRIBUTE_TYPE = 0xE1; // Date - ZCL_UTC_ATTRIBUTE_TYPE = 0xE2; // UTC Time - ZCL_EPOCH_US_ATTRIBUTE_TYPE = 0xE3; // Epoch Microseconds - ZCL_EPOCH_S_ATTRIBUTE_TYPE = 0xE4; // Epoch Seconds - ZCL_SYSTIME_US_ATTRIBUTE_TYPE = 0xE5; // System Time Microseconds - ZCL_PERCENT_ATTRIBUTE_TYPE = 0xE6; // Percentage units 1% - ZCL_PERCENT100THS_ATTRIBUTE_TYPE = 0xE7; // Percentage units 0.01% - ZCL_CLUSTER_ID_ATTRIBUTE_TYPE = 0xE8; // Cluster ID - ZCL_ATTRIB_ID_ATTRIBUTE_TYPE = 0xE9; // Attribute ID - ZCL_FIELD_ID_ATTRIBUTE_TYPE = 0xEA; // Field ID - ZCL_EVENT_ID_ATTRIBUTE_TYPE = 0xEB; // Event ID - ZCL_COMMAND_ID_ATTRIBUTE_TYPE = 0xEC; // Command ID - ZCL_ACTION_ID_ATTRIBUTE_TYPE = 0xED; // Action ID - ZCL_TRANS_ID_ATTRIBUTE_TYPE = 0xEF; // Transaction ID - ZCL_NODE_ID_ATTRIBUTE_TYPE = 0xF0; // Node ID - ZCL_VENDOR_ID_ATTRIBUTE_TYPE = 0xF1; // Vendor ID - ZCL_DEVTYPE_ID_ATTRIBUTE_TYPE = 0xF2; // Device Type ID - ZCL_FABRIC_ID_ATTRIBUTE_TYPE = 0xF3; // Fabric ID - ZCL_GROUP_ID_ATTRIBUTE_TYPE = 0xF4; // Group ID - ZCL_STATUS_ATTRIBUTE_TYPE = 0xF5; // Status Code - ZCL_DATA_VER_ATTRIBUTE_TYPE = 0xF6; // Data Version - ZCL_EVENT_NO_ATTRIBUTE_TYPE = 0xF7; // Event Number - ZCL_ENDPOINT_NO_ATTRIBUTE_TYPE = 0xF8; // Endpoint Number - ZCL_FABRIC_IDX_ATTRIBUTE_TYPE = 0xF9; // Fabric Index - ZCL_IPADR_ATTRIBUTE_TYPE = 0xFA; // IP Address - ZCL_IPV4ADR_ATTRIBUTE_TYPE = 0xFB; // IPv4 Address - ZCL_IPV6ADR_ATTRIBUTE_TYPE = 0xFC; // IPv6 Address - ZCL_IPV6PRE_ATTRIBUTE_TYPE = 0xFD; // IPv6 Prefix - ZCL_HWADR_ATTRIBUTE_TYPE = 0xFE; // Hardware Address - ZCL_UNKNOWN_ATTRIBUTE_TYPE = 0xFF; // Unknown + ZCL_NO_DATA_ATTRIBUTE_TYPE = 0x00; // No data + ZCL_BOOLEAN_ATTRIBUTE_TYPE = 0x10; // Boolean + ZCL_BITMAP8_ATTRIBUTE_TYPE = 0x18; // 8-bit bitmap + ZCL_BITMAP16_ATTRIBUTE_TYPE = 0x19; // 16-bit bitmap + ZCL_BITMAP32_ATTRIBUTE_TYPE = 0x1B; // 32-bit bitmap + ZCL_BITMAP64_ATTRIBUTE_TYPE = 0x1F; // 64-bit bitmap + ZCL_INT8U_ATTRIBUTE_TYPE = 0x20; // Unsigned 8-bit integer + ZCL_INT16U_ATTRIBUTE_TYPE = 0x21; // Unsigned 16-bit integer + ZCL_INT24U_ATTRIBUTE_TYPE = 0x22; // Unsigned 24-bit integer + ZCL_INT32U_ATTRIBUTE_TYPE = 0x23; // Unsigned 32-bit integer + ZCL_INT40U_ATTRIBUTE_TYPE = 0x24; // Unsigned 40-bit integer + ZCL_INT48U_ATTRIBUTE_TYPE = 0x25; // Unsigned 48-bit integer + ZCL_INT56U_ATTRIBUTE_TYPE = 0x26; // Unsigned 56-bit integer + ZCL_INT64U_ATTRIBUTE_TYPE = 0x27; // Unsigned 64-bit integer + ZCL_INT8S_ATTRIBUTE_TYPE = 0x28; // Signed 8-bit integer + ZCL_INT16S_ATTRIBUTE_TYPE = 0x29; // Signed 16-bit integer + ZCL_INT24S_ATTRIBUTE_TYPE = 0x2A; // Signed 24-bit integer + ZCL_INT32S_ATTRIBUTE_TYPE = 0x2B; // Signed 32-bit integer + ZCL_INT40S_ATTRIBUTE_TYPE = 0x2C; // Signed 40-bit integer + ZCL_INT48S_ATTRIBUTE_TYPE = 0x2D; // Signed 48-bit integer + ZCL_INT56S_ATTRIBUTE_TYPE = 0x2E; // Signed 56-bit integer + ZCL_INT64S_ATTRIBUTE_TYPE = 0x2F; // Signed 64-bit integer + ZCL_ENUM8_ATTRIBUTE_TYPE = 0x30; // 8-bit enumeration + ZCL_ENUM16_ATTRIBUTE_TYPE = 0x31; // 16-bit enumeration + ZCL_SINGLE_ATTRIBUTE_TYPE = 0x39; // Single precision + ZCL_DOUBLE_ATTRIBUTE_TYPE = 0x3A; // Double precision + ZCL_OCTET_STRING_ATTRIBUTE_TYPE = 0x41; // Octet String + ZCL_CHAR_STRING_ATTRIBUTE_TYPE = 0x42; // Character String + ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE = 0x43; // Long Octet String + ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE = 0x44; // Long Character String + ZCL_ARRAY_ATTRIBUTE_TYPE = 0x48; // List + ZCL_STRUCT_ATTRIBUTE_TYPE = 0x4C; // Structure + ZCL_TOD_ATTRIBUTE_TYPE = 0xE0; // Time of day + ZCL_DATE_ATTRIBUTE_TYPE = 0xE1; // Date + ZCL_UTC_ATTRIBUTE_TYPE = 0xE2; // UTC Time + ZCL_EPOCH_US_ATTRIBUTE_TYPE = 0xE3; // Epoch Microseconds + ZCL_EPOCH_S_ATTRIBUTE_TYPE = 0xE4; // Epoch Seconds + ZCL_SYSTIME_US_ATTRIBUTE_TYPE = 0xE5; // System Time Microseconds + ZCL_PERCENT_ATTRIBUTE_TYPE = 0xE6; // Percentage units 1% + ZCL_PERCENT100THS_ATTRIBUTE_TYPE = 0xE7; // Percentage units 0.01% + ZCL_CLUSTER_ID_ATTRIBUTE_TYPE = 0xE8; // Cluster ID + ZCL_ATTRIB_ID_ATTRIBUTE_TYPE = 0xE9; // Attribute ID + ZCL_FIELD_ID_ATTRIBUTE_TYPE = 0xEA; // Field ID + ZCL_EVENT_ID_ATTRIBUTE_TYPE = 0xEB; // Event ID + ZCL_COMMAND_ID_ATTRIBUTE_TYPE = 0xEC; // Command ID + ZCL_ACTION_ID_ATTRIBUTE_TYPE = 0xED; // Action ID + ZCL_TRANS_ID_ATTRIBUTE_TYPE = 0xEF; // Transaction ID + ZCL_NODE_ID_ATTRIBUTE_TYPE = 0xF0; // Node ID + ZCL_VENDOR_ID_ATTRIBUTE_TYPE = 0xF1; // Vendor ID + ZCL_DEVTYPE_ID_ATTRIBUTE_TYPE = 0xF2; // Device Type ID + ZCL_FABRIC_ID_ATTRIBUTE_TYPE = 0xF3; // Fabric ID + ZCL_GROUP_ID_ATTRIBUTE_TYPE = 0xF4; // Group ID + ZCL_STATUS_ATTRIBUTE_TYPE = 0xF5; // Status Code + ZCL_DATA_VER_ATTRIBUTE_TYPE = 0xF6; // Data Version + ZCL_EVENT_NO_ATTRIBUTE_TYPE = 0xF7; // Event Number + ZCL_ENDPOINT_NO_ATTRIBUTE_TYPE = 0xF8; // Endpoint Number + ZCL_FABRIC_IDX_ATTRIBUTE_TYPE = 0xF9; // Fabric Index + ZCL_IPADR_ATTRIBUTE_TYPE = 0xFA; // IP Address + ZCL_IPV4ADR_ATTRIBUTE_TYPE = 0xFB; // IPv4 Address + ZCL_IPV6ADR_ATTRIBUTE_TYPE = 0xFC; // IPv6 Address + ZCL_IPV6PRE_ATTRIBUTE_TYPE = 0xFD; // IPv6 Prefix + ZCL_HWADR_ATTRIBUTE_TYPE = 0xFE; // Hardware Address + ZCL_UNKNOWN_ATTRIBUTE_TYPE = 0xFF; // Unknown } enum ClusterType { - ZCL_INVALID_CLUSTER_ID = 0x0000; - ZCL_POWER_CONFIG_CLUSTER_ID = 0x0001; - ZCL_DEVICE_TEMP_CLUSTER_ID = 0x0002; - ZCL_IDENTIFY_CLUSTER_ID = 0x0003; - ZCL_GROUPS_CLUSTER_ID = 0x0004; - ZCL_ON_OFF_CLUSTER_ID = 0x0006; - ZCL_LEVEL_CONTROL_CLUSTER_ID = 0x0008; - ZCL_ALARM_CLUSTER_ID = 0x0009; - ZCL_TIME_CLUSTER_ID = 0x000A; - ZCL_POWER_PROFILE_CLUSTER_ID = 0x001A; - ZCL_APPLIANCE_CONTROL_CLUSTER_ID = 0x001B; - ZCL_DESCRIPTOR_CLUSTER_ID = 0x001D; - ZCL_POLL_CONTROL_CLUSTER_ID = 0x0020; - ZCL_ACTIONS_CLUSTER_ID = 0x0025; - ZCL_BASIC_CLUSTER_ID = 0x0028; - ZCL_OTA_SOFTWARE_UPDATE_PROVIDER_CLUSTER_ID = 0x0029; - ZCL_OTA_SOFTWARE_UPDATE_REQUESTOR_CLUSTER_ID = 0x002A; - ZCL_UNIT_LOCALIZATION_CLUSTER_ID = 0x002D; - ZCL_POWER_SOURCE_CLUSTER_ID = 0x002F; - ZCL_GENERAL_COMMISSIONING_CLUSTER_ID = 0x0030; - ZCL_NETWORK_COMMISSIONING_CLUSTER_ID = 0x0031; - ZCL_DIAGNOSTIC_LOGS_CLUSTER_ID = 0x0032; - ZCL_GENERAL_DIAGNOSTICS_CLUSTER_ID = 0x0033; - ZCL_SOFTWARE_DIAGNOSTICS_CLUSTER_ID = 0x0034; - ZCL_THREAD_NETWORK_DIAGNOSTICS_CLUSTER_ID = 0x0035; - ZCL_WIFI_NETWORK_DIAGNOSTICS_CLUSTER_ID = 0x0036; - ZCL_ETHERNET_NETWORK_DIAGNOSTICS_CLUSTER_ID = 0x0037; - ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_ID = 0x0039; - ZCL_SWITCH_CLUSTER_ID = 0x003B; - ZCL_ADMINISTRATOR_COMMISSIONING_CLUSTER_ID = 0x003C; - ZCL_OPERATIONAL_CREDENTIALS_CLUSTER_ID = 0x003E; - ZCL_FIXED_LABEL_CLUSTER_ID = 0x0040; - ZCL_BOOLEAN_STATE_CLUSTER_ID = 0x0045; - ZCL_MODE_SELECT_CLUSTER_ID = 0x0050; - ZCL_LAUNDRY_WASHER_MODE_CLUSTER_ID = 0x0051; - ZCL_REFRIGERATOR_AND_TEMPERATURE_CONTROLLED_CABINET_MODE_CLUSTER_ID = 0x0052; - ZCL_LAUNDRY_WASHER_CONTROLS_CLUSTER_ID = 0x0053; - ZCL_RVC_RUN_MODE_CLUSTER_ID = 0x0054; - ZCL_RVC_CLEAN_MODE_CLUSTER_ID = 0x0055; - ZCL_TEMPERATURE_CONTROL_CLUSTER_ID = 0x0056; - ZCL_REFRIGERATOR_ALARM_CLUSTER_ID = 0x0057; - ZCL_DISHWASHER_MODE_CLUSTER_ID = 0x0059; - ZCL_AIR_QUALITY_CLUSTER_ID = 0x005B; - ZCL_DISHWASHER_ALARM_CLUSTER_ID = 0x005D; - ZCL_SMOKE_CO_ALARM_ID = 0x005C; - ZCL_OPERATIONAL_STATE_CLUSTER_ID = 0x0060; - ZCL_RVC_OPERATIONAL_STATE_CLUSTER_ID = 0x0061; - ZCL_HEPA_FILTER_MONITORING_CLUSTER_ID = 0x0071; - ZCL_ACTIVATED_CARBON_FILTER_MONITORING_CLUSTER_ID = 0x0072; - ZCL_SHADE_CONFIG_CLUSTER_ID = 0x0100; - ZCL_DOOR_LOCK_CLUSTER_ID = 0x0101; - ZCL_WINDOW_COVERING_CLUSTER_ID = 0x0102; - ZCL_PUMP_CONFIGURATION_AND_CONTROL_CLUSTER_ID = 0x0200; - ZCL_THERMOSTAT_CLUSTER_ID = 0x0201; - ZCL_FAN_CONTROL_CLUSTER_ID = 0x0202; - ZCL_DEHUMID_CONTROL_CLUSTER_ID = 0x0203; - ZCL_THERMOSTAT_USER_INTERFACE_CONFIGURATION_CLUSTER_ID = 0x0204; - ZCL_COLOR_CONTROL_CLUSTER_ID = 0x0300; - ZCL_BALLAST_CONFIGURATION_CLUSTER_ID = 0x0301; - ZCL_ILLUMINANCE_MEASUREMENT_CLUSTER_ID = 0x0400; - ZCL_TEMPERATURE_MEASUREMENT_CLUSTER_ID = 0x0402; - ZCL_PRESSURE_MEASUREMENT_CLUSTER_ID = 0x0403; - ZCL_FLOW_MEASUREMENT_CLUSTER_ID = 0x0404; - ZCL_RELATIVE_HUMIDITY_MEASUREMENT_CLUSTER_ID = 0x0405; - ZCL_OCCUPANCY_SENSING_CLUSTER_ID = 0x0406; - ZCL_CARBON_MONOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x040C; - ZCL_CARBON_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x040D; - ZCL_ETHYLENE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x040E; - ZCL_ETHYLENE_OXIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x040F; - ZCL_HYDROGEN_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0410; - ZCL_HYDROGEN_SULPHIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0411; - ZCL_NITRIC_OXIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0412; - ZCL_NITROGEN_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0413; - ZCL_OXYGEN_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0414; - ZCL_OZONE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0415; - ZCL_SULFUR_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0416; - ZCL_DISSOLVED_OXYGEN_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0417; - ZCL_BROMATE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0418; - ZCL_CHLORAMINES_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0419; - ZCL_CHLORINE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x041A; - ZCL_FECAL_COLIFORM_AND_E_COLI_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x041B; - ZCL_FLUORIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x041C; - ZCL_HALOACETIC_ACIDS_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x041D; - ZCL_TOTAL_TRIHALOMETHANES_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x041E; - ZCL_TOTAL_COLIFORM_BACTERIA_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x041F; - ZCL_TURBIDITY_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0420; - ZCL_COPPER_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0421; - ZCL_LEAD_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0422; - ZCL_MANGANESE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0423; - ZCL_SULFATE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0424; - ZCL_BROMODICHLOROMETHANE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0425; - ZCL_BROMOFORM_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0426; - ZCL_CHLORODIBROMOMETHANE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0427; - ZCL_CHLOROFORM_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0428; - ZCL_SODIUM_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0429; - ZCL_PM2_5_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x042A; - ZCL_FORMALDEHYDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x042B; - ZCL_PM1_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x042C; - ZCL_PM10_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x042D; - ZCL_TOTAL_VOLATILE_ORGANIC_COMPOUNDS_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x042E; - ZCL_RADON_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x042F; - ZCL_WAKE_ON_LAN_CLUSTER_ID = 0x0503; - ZCL_CHANNEL_CLUSTER_ID = 0x0504; - ZCL_TARGET_NAVIGATOR_CLUSTER_ID = 0x0505; - ZCL_MEDIA_PLAYBACK_CLUSTER_ID = 0x0506; - ZCL_MEDIA_INPUT_CLUSTER_ID = 0x0507; - ZCL_LOW_POWER_CLUSTER_ID = 0x0508; - ZCL_KEYPAD_INPUT_CLUSTER_ID = 0x0509; - ZCL_CONTENT_LAUNCHER_CLUSTER_ID = 0x050A; - ZCL_AUDIO_OUTPUT_CLUSTER_ID = 0x050B; - ZCL_APPLICATION_LAUNCHER_CLUSTER_ID = 0x050C; - ZCL_APPLICATION_BASIC_CLUSTER_ID = 0x050D; - ZCL_ACCOUNT_LOGIN_CLUSTER_ID = 0x050E; - ZCL_CONTENT_CONTROL_CLUSTER_ID = 0x050F; - ZCL_MESSAGING_CLUSTER_ID = 0x0703; - ZCL_MESSAGES_CLUSTER_ID = 0x0097; - ZCL_APPLIANCE_IDENTIFICATION_CLUSTER_ID = 0x0B00; - ZCL_METER_IDENTIFICATION_CLUSTER_ID = 0x0B01; - ZCL_APPLIANCE_EVENTS_AND_ALERT_CLUSTER_ID = 0x0B02; - ZCL_APPLIANCE_STATISTICS_CLUSTER_ID = 0x0B03; - ZCL_SAMPLE_MFG_SPECIFIC_CLUSTER_ID = 0xFC00; + ZCL_INVALID_CLUSTER_ID = 0x0000; ZCL_POWER_CONFIG_CLUSTER_ID = 0x0001; + ZCL_DEVICE_TEMP_CLUSTER_ID = 0x0002; + ZCL_IDENTIFY_CLUSTER_ID = 0x0003; + ZCL_GROUPS_CLUSTER_ID = 0x0004; + ZCL_ON_OFF_CLUSTER_ID = 0x0006; + ZCL_LEVEL_CONTROL_CLUSTER_ID = 0x0008; + ZCL_ALARM_CLUSTER_ID = 0x0009; + ZCL_TIME_CLUSTER_ID = 0x000A; + ZCL_POWER_PROFILE_CLUSTER_ID = 0x001A; + ZCL_APPLIANCE_CONTROL_CLUSTER_ID = 0x001B; + ZCL_DESCRIPTOR_CLUSTER_ID = 0x001D; + ZCL_POLL_CONTROL_CLUSTER_ID = 0x0020; + ZCL_ACTIONS_CLUSTER_ID = 0x0025; + ZCL_BASIC_CLUSTER_ID = 0x0028; + ZCL_OTA_SOFTWARE_UPDATE_PROVIDER_CLUSTER_ID = 0x0029; + ZCL_OTA_SOFTWARE_UPDATE_REQUESTOR_CLUSTER_ID = 0x002A; + ZCL_UNIT_LOCALIZATION_CLUSTER_ID = 0x002D; + ZCL_POWER_SOURCE_CLUSTER_ID = 0x002F; + ZCL_GENERAL_COMMISSIONING_CLUSTER_ID = 0x0030; + ZCL_NETWORK_COMMISSIONING_CLUSTER_ID = 0x0031; + ZCL_DIAGNOSTIC_LOGS_CLUSTER_ID = 0x0032; + ZCL_GENERAL_DIAGNOSTICS_CLUSTER_ID = 0x0033; + ZCL_SOFTWARE_DIAGNOSTICS_CLUSTER_ID = 0x0034; + ZCL_THREAD_NETWORK_DIAGNOSTICS_CLUSTER_ID = 0x0035; + ZCL_WIFI_NETWORK_DIAGNOSTICS_CLUSTER_ID = 0x0036; + ZCL_ETHERNET_NETWORK_DIAGNOSTICS_CLUSTER_ID = 0x0037; + ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_ID = 0x0039; + ZCL_SWITCH_CLUSTER_ID = 0x003B; + ZCL_ADMINISTRATOR_COMMISSIONING_CLUSTER_ID = 0x003C; + ZCL_OPERATIONAL_CREDENTIALS_CLUSTER_ID = 0x003E; + ZCL_FIXED_LABEL_CLUSTER_ID = 0x0040; + ZCL_BOOLEAN_STATE_CLUSTER_ID = 0x0045; + ZCL_MODE_SELECT_CLUSTER_ID = 0x0050; + ZCL_LAUNDRY_WASHER_MODE_CLUSTER_ID = 0x0051; + ZCL_REFRIGERATOR_AND_TEMPERATURE_CONTROLLED_CABINET_MODE_CLUSTER_ID = 0x0052; + ZCL_LAUNDRY_WASHER_CONTROLS_CLUSTER_ID = 0x0053; + ZCL_RVC_RUN_MODE_CLUSTER_ID = 0x0054; + ZCL_RVC_CLEAN_MODE_CLUSTER_ID = 0x0055; + ZCL_TEMPERATURE_CONTROL_CLUSTER_ID = 0x0056; + ZCL_REFRIGERATOR_ALARM_CLUSTER_ID = 0x0057; + ZCL_DISHWASHER_MODE_CLUSTER_ID = 0x0059; + ZCL_AIR_QUALITY_CLUSTER_ID = 0x005B; + ZCL_DISHWASHER_ALARM_CLUSTER_ID = 0x005D; + ZCL_SMOKE_CO_ALARM_ID = 0x005C; + ZCL_OPERATIONAL_STATE_CLUSTER_ID = 0x0060; + ZCL_RVC_OPERATIONAL_STATE_CLUSTER_ID = 0x0061; + ZCL_HEPA_FILTER_MONITORING_CLUSTER_ID = 0x0071; + ZCL_ACTIVATED_CARBON_FILTER_MONITORING_CLUSTER_ID = 0x0072; + ZCL_SHADE_CONFIG_CLUSTER_ID = 0x0100; + ZCL_DOOR_LOCK_CLUSTER_ID = 0x0101; + ZCL_WINDOW_COVERING_CLUSTER_ID = 0x0102; + ZCL_PUMP_CONFIGURATION_AND_CONTROL_CLUSTER_ID = 0x0200; + ZCL_THERMOSTAT_CLUSTER_ID = 0x0201; + ZCL_FAN_CONTROL_CLUSTER_ID = 0x0202; + ZCL_DEHUMID_CONTROL_CLUSTER_ID = 0x0203; + ZCL_THERMOSTAT_USER_INTERFACE_CONFIGURATION_CLUSTER_ID = 0x0204; + ZCL_COLOR_CONTROL_CLUSTER_ID = 0x0300; + ZCL_BALLAST_CONFIGURATION_CLUSTER_ID = 0x0301; + ZCL_ILLUMINANCE_MEASUREMENT_CLUSTER_ID = 0x0400; + ZCL_TEMPERATURE_MEASUREMENT_CLUSTER_ID = 0x0402; + ZCL_PRESSURE_MEASUREMENT_CLUSTER_ID = 0x0403; + ZCL_FLOW_MEASUREMENT_CLUSTER_ID = 0x0404; + ZCL_RELATIVE_HUMIDITY_MEASUREMENT_CLUSTER_ID = 0x0405; + ZCL_OCCUPANCY_SENSING_CLUSTER_ID = 0x0406; + ZCL_CARBON_MONOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x040C; + ZCL_CARBON_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x040D; + ZCL_ETHYLENE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x040E; + ZCL_ETHYLENE_OXIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x040F; + ZCL_HYDROGEN_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0410; + ZCL_HYDROGEN_SULPHIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0411; + ZCL_NITRIC_OXIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0412; + ZCL_NITROGEN_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0413; + ZCL_OXYGEN_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0414; + ZCL_OZONE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0415; + ZCL_SULFUR_DIOXIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0416; + ZCL_DISSOLVED_OXYGEN_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0417; + ZCL_BROMATE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0418; + ZCL_CHLORAMINES_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0419; + ZCL_CHLORINE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x041A; + ZCL_FECAL_COLIFORM_AND_E_COLI_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x041B; + ZCL_FLUORIDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x041C; + ZCL_HALOACETIC_ACIDS_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x041D; + ZCL_TOTAL_TRIHALOMETHANES_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x041E; + ZCL_TOTAL_COLIFORM_BACTERIA_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x041F; + ZCL_TURBIDITY_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0420; + ZCL_COPPER_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0421; + ZCL_LEAD_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0422; + ZCL_MANGANESE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0423; + ZCL_SULFATE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0424; + ZCL_BROMODICHLOROMETHANE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0425; + ZCL_BROMOFORM_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0426; + ZCL_CHLORODIBROMOMETHANE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0427; + ZCL_CHLOROFORM_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0428; + ZCL_SODIUM_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x0429; + ZCL_PM2_5_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x042A; + ZCL_FORMALDEHYDE_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x042B; + ZCL_PM1_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x042C; + ZCL_PM10_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x042D; + ZCL_TOTAL_VOLATILE_ORGANIC_COMPOUNDS_CONCENTRATION_MEASUREMENT_CLUSTER_ID = + 0x042E; + ZCL_RADON_CONCENTRATION_MEASUREMENT_CLUSTER_ID = 0x042F; + ZCL_WAKE_ON_LAN_CLUSTER_ID = 0x0503; + ZCL_CHANNEL_CLUSTER_ID = 0x0504; + ZCL_TARGET_NAVIGATOR_CLUSTER_ID = 0x0505; + ZCL_MEDIA_PLAYBACK_CLUSTER_ID = 0x0506; + ZCL_MEDIA_INPUT_CLUSTER_ID = 0x0507; + ZCL_LOW_POWER_CLUSTER_ID = 0x0508; + ZCL_KEYPAD_INPUT_CLUSTER_ID = 0x0509; + ZCL_CONTENT_LAUNCHER_CLUSTER_ID = 0x050A; + ZCL_AUDIO_OUTPUT_CLUSTER_ID = 0x050B; + ZCL_APPLICATION_LAUNCHER_CLUSTER_ID = 0x050C; + ZCL_APPLICATION_BASIC_CLUSTER_ID = 0x050D; + ZCL_ACCOUNT_LOGIN_CLUSTER_ID = 0x050E; + ZCL_CONTENT_CONTROL_CLUSTER_ID = 0x050F; + ZCL_MESSAGING_CLUSTER_ID = 0x0703; + ZCL_MESSAGES_CLUSTER_ID = 0x0097; + ZCL_APPLIANCE_IDENTIFICATION_CLUSTER_ID = 0x0B00; + ZCL_METER_IDENTIFICATION_CLUSTER_ID = 0x0B01; + ZCL_APPLIANCE_EVENTS_AND_ALERT_CLUSTER_ID = 0x0B02; + ZCL_APPLIANCE_STATISTICS_CLUSTER_ID = 0x0B03; + ZCL_SAMPLE_MFG_SPECIFIC_CLUSTER_ID = 0xFC00; - // NOTE: This is a large number that becomes negative as a 32-bit integer. - // - // Protobuf documentation states: - // Enumerator constants must be in the range of a 32-bit integer. Since enum values - // use varint encoding on the wire, negative values are inefficient and thus not recommended. - ZCL_TEST_CLUSTER_ID = -918523; // 0xFFF1FC05; + // NOTE: This is a large number that becomes negative as a 32-bit integer. + // + // Protobuf documentation states: + // Enumerator constants must be in the range of a 32-bit integer. Since enum + // values use varint encoding on the wire, negative values are inefficient + // and thus not recommended. + ZCL_TEST_CLUSTER_ID = -918523; // 0xFFF1FC05; } - message AttributeMetadata { uint32 endpoint = 1; ClusterType cluster = 2; @@ -220,6 +220,7 @@ message AttributeData { int32 data_int16 = 7; int32 data_int32 = 8; float data_single = 10; + string data_string = 11; }; optional bytes tlv_data = 9; } @@ -230,6 +231,6 @@ message AttributeWrite { } service Attributes { - rpc Write(AttributeWrite) returns (pw.protobuf.Empty){} - rpc Read(AttributeMetadata) returns (AttributeData){} + rpc Write(AttributeWrite) returns(pw.protobuf.Empty) {} + rpc Read(AttributeMetadata) returns(AttributeData) {} } diff --git a/examples/common/pigweed/rpc_services/Attributes.h b/examples/common/pigweed/rpc_services/Attributes.h index c7f102a0e6ba24..cfbb400ae2f7f2 100644 --- a/examples/common/pigweed/rpc_services/Attributes.h +++ b/examples/common/pigweed/rpc_services/Attributes.h @@ -18,6 +18,7 @@ #pragma once +#include "attributes_service/attributes_service.pb.h" #include "attributes_service/attributes_service.rpc.pb.h" #include "pigweed/rpc_services/internal/StatusUtils.h" @@ -44,46 +45,177 @@ namespace rpc { class Attributes : public pw_rpc::nanopb::Attributes::Service { public: - ::pw::Status Write(const chip_rpc_AttributeWrite & request, pw_protobuf_Empty & response) + static constexpr TLV::Tag kAttributeDataTag = TLV::ContextTag(1); + static constexpr TLV::Tag kDataTag = TLV::ContextTag(to_underlying(chip::app::AttributeDataIB::Tag::kData)); + + CHIP_ERROR PositionOnDataElement(chip::TLV::TLVReader & reader) { - const void * data; - DeviceLayer::StackLock lock; + // Expect the TLV to be the full structure as received from a read (or subset) + // TLV is a full ReportDataMessage + // - Anonymous Structure (container of everything) + // - 1: Array (one element) + // - Anonymous (the element) + // - 1 (AttributeData/AttributeDataIB) - Structure + // - 0 - Data Version + // - 1 - Path (1: Node, 2: Endpoint, 3: Cluster, 4: Attribute, ...) + // - 2 - Data (variable - may be raw data or a Structure) + + TLV::TLVType unused_outer_type; + + // Enter anonymous wrapper + ReturnErrorOnFailure(reader.Next()); // got to anonymous + ReturnErrorOnFailure(reader.EnterContainer(unused_outer_type)); + + // Enter the array + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(reader.EnterContainer(unused_outer_type)); + + // enter the structure of data + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(reader.EnterContainer(unused_outer_type)); + + // Find AttributeData Container + { + chip::TLV::TLVReader tmp; + ReturnErrorOnFailure(reader.FindElementWithTag(kAttributeDataTag, tmp)); + reader = tmp; + } + + // Enter into AttributeData Container + ReturnErrorOnFailure(reader.EnterContainer(unused_outer_type)); + + // Find Data Container + { + chip::TLV::TLVReader tmp; + ReturnErrorOnFailure(reader.FindElementWithTag(kDataTag, tmp)); + reader = tmp; + } + + return CHIP_NO_ERROR; + } + + pw::Result ReadIntoTlv(const chip_rpc_AttributeData & data, chip::MutableByteSpan tempBuffer) + { + TLV::TLVReader result; + + if (data.has_tlv_data) + { + result.Init(data.tlv_data.bytes, data.tlv_data.size); + CHIP_ERROR err = PositionOnDataElement(result); + if (err != CHIP_NO_ERROR) + { + ChipLogError(Support, "Failed to parse input TLV buffer: %" CHIP_ERROR_FORMAT, err.Format()); + return pw::Status::InvalidArgument(); + } + + return result; + } - switch (request.data.which_data) + TLV::TLVWriter writer; + + writer.Init(tempBuffer); + + CHIP_ERROR write_status; + + TLV::TLVType outer; + VerifyOrReturnError(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer) == CHIP_NO_ERROR, + pw::Status::Internal()); + + switch (data.which_data) { case chip_rpc_AttributeData_data_bool_tag: - data = &request.data.data.data_bool; + write_status = writer.Put(kDataTag, data.data.data_bool); break; case chip_rpc_AttributeData_data_uint8_tag: - data = &request.data.data.data_uint8; + write_status = writer.Put(kDataTag, data.data.data_uint8); break; case chip_rpc_AttributeData_data_uint16_tag: - data = &request.data.data.data_uint16; + write_status = writer.Put(kDataTag, data.data.data_uint16); break; case chip_rpc_AttributeData_data_uint32_tag: - data = &request.data.data.data_uint32; + write_status = writer.Put(kDataTag, data.data.data_uint32); break; case chip_rpc_AttributeData_data_int8_tag: - data = &request.data.data.data_int8; + write_status = writer.Put(kDataTag, data.data.data_int8); break; case chip_rpc_AttributeData_data_int16_tag: - data = &request.data.data.data_int16; + write_status = writer.Put(kDataTag, data.data.data_int16); break; case chip_rpc_AttributeData_data_int32_tag: - data = &request.data.data.data_int32; + write_status = writer.Put(kDataTag, data.data.data_int32); + break; + case chip_rpc_AttributeData_data_single_tag: + write_status = writer.Put(kDataTag, data.data.data_single); break; case chip_rpc_AttributeData_data_bytes_tag: - data = &request.data.data.data_bytes; + write_status = writer.PutBytes(kDataTag, data.data.data_bytes.bytes, data.data.data_bytes.size); break; - case chip_rpc_AttributeData_data_single_tag: - data = &request.data.data.data_single; + case chip_rpc_AttributeData_data_string_tag: + write_status = writer.PutString(kDataTag, data.data.data_string); break; default: return pw::Status::InvalidArgument(); } - RETURN_STATUS_IF_NOT_OK( - emberAfWriteAttribute(request.metadata.endpoint, request.metadata.cluster, request.metadata.attribute_id, - const_cast(static_cast(data)), request.metadata.type)); + + if (write_status != CHIP_NO_ERROR) + { + ChipLogError(Support, "Failed to encode TLV data: %" CHIP_ERROR_FORMAT, write_status.Format()); + return pw::Status::Internal(); + } + + VerifyOrReturnValue(writer.EndContainer(outer) == CHIP_NO_ERROR, pw::Status::Internal()); + VerifyOrReturnValue(writer.Finalize() == CHIP_NO_ERROR, pw::Status::Internal()); + result.Init(tempBuffer.data(), writer.GetLengthWritten()); + + VerifyOrReturnError(result.Next() == CHIP_NO_ERROR, pw::Status::Internal()); + VerifyOrReturnError(result.EnterContainer(outer) == CHIP_NO_ERROR, pw::Status::Internal()); + + // This positions on the data element + VerifyOrReturnError(result.Next() == CHIP_NO_ERROR, pw::Status::Internal()); + + return result; + } + + ::pw::Status Write(const chip_rpc_AttributeWrite & request, pw_protobuf_Empty & response) + { + app::ConcreteAttributePath path(request.metadata.endpoint, request.metadata.cluster, request.metadata.attribute_id); + + DeviceLayer::StackLock lock; + + // TODO: this assumes a singleton data model provider + app::DataModel::Provider * provider = app::InteractionModelEngine::GetInstance()->GetDataModelProvider(); + + app::DataModel::ServerClusterFinder serverClusterFinder(provider); + auto info = serverClusterFinder.Find(path); + if (!info.has_value()) + { + return ::pw::Status::NotFound(); + } + + Access::SubjectDescriptor subjectDescriptor{ .authMode = chip::Access::AuthMode::kPase }; + app::DataModel::WriteAttributeRequest write_request; + write_request.path = path; + write_request.operationFlags.Set(app::DataModel::OperationFlags::kInternal); + write_request.subjectDescriptor = &subjectDescriptor; + + uint8_t raw_value_buffer[64]; // enough to hold general types + pw::Result tlvReader = ReadIntoTlv(request.data, chip::MutableByteSpan(raw_value_buffer)); + + if (!tlvReader.status().ok()) + { + return tlvReader.status(); + } + + app::AttributeValueDecoder decoder(tlvReader.value(), subjectDescriptor); + app::DataModel::ActionReturnStatus result = provider->WriteAttribute(write_request, decoder); + + if (!result.IsSuccess()) + { + app::DataModel::ActionReturnStatus::StringStorage storage; + ChipLogError(Support, "Failed to write data: %s", result.c_str(storage)); + return ::pw::Status::Internal(); + } + return pw::OkStatus(); } @@ -92,6 +224,7 @@ class Attributes : public pw_rpc::nanopb::Attributes::Service app::ConcreteAttributePath path(request.endpoint, request.cluster, request.attribute_id); MutableByteSpan tlvBuffer(response.tlv_data.bytes); PW_TRY(ReadAttributeIntoTlvBuffer(path, tlvBuffer)); + // NOTE: TLV will be a full AttributeReportIB (so not purely the data) response.tlv_data.size = tlvBuffer.size(); response.has_tlv_data = true; @@ -137,6 +270,16 @@ class Attributes : public pw_rpc::nanopb::Attributes::Service PW_TRY(TlvBufferGetData(tlvBuffer, TLV::kTLVType_FloatingPointNumber, response.data.data_single)); response.which_data = chip_rpc_AttributeData_data_single_tag; break; + case chip_rpc_AttributeType_ZCL_OCTET_STRING_ATTRIBUTE_TYPE: + case chip_rpc_AttributeType_ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE: + PW_TRY(TlvBufferGetData(tlvBuffer, TLV::kTLVType_ByteString, response.data.data_bytes)); + response.which_data = chip_rpc_AttributeData_data_bytes_tag; + break; + case chip_rpc_AttributeType_ZCL_CHAR_STRING_ATTRIBUTE_TYPE: + case chip_rpc_AttributeType_ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE: + PW_TRY(TlvBufferGetData(tlvBuffer, TLV::kTLVType_UTF8String, response.data.data_string)); + response.which_data = chip_rpc_AttributeData_data_string_tag; + break; case chip_rpc_AttributeType_ZCL_BITMAP8_ATTRIBUTE_TYPE: case chip_rpc_AttributeType_ZCL_BITMAP16_ATTRIBUTE_TYPE: case chip_rpc_AttributeType_ZCL_BITMAP32_ATTRIBUTE_TYPE: @@ -153,10 +296,6 @@ class Attributes : public pw_rpc::nanopb::Attributes::Service case chip_rpc_AttributeType_ZCL_INT56S_ATTRIBUTE_TYPE: case chip_rpc_AttributeType_ZCL_INT64S_ATTRIBUTE_TYPE: case chip_rpc_AttributeType_ZCL_DOUBLE_ATTRIBUTE_TYPE: - case chip_rpc_AttributeType_ZCL_OCTET_STRING_ATTRIBUTE_TYPE: - case chip_rpc_AttributeType_ZCL_CHAR_STRING_ATTRIBUTE_TYPE: - case chip_rpc_AttributeType_ZCL_LONG_OCTET_STRING_ATTRIBUTE_TYPE: - case chip_rpc_AttributeType_ZCL_LONG_CHAR_STRING_ATTRIBUTE_TYPE: case chip_rpc_AttributeType_ZCL_STRUCT_ATTRIBUTE_TYPE: case chip_rpc_AttributeType_ZCL_TOD_ATTRIBUTE_TYPE: case chip_rpc_AttributeType_ZCL_DATE_ATTRIBUTE_TYPE: @@ -249,6 +388,24 @@ class Attributes : public pw_rpc::nanopb::Attributes::Service return ::pw::OkStatus(); } + template + CHIP_ERROR TlvGet(TLV::TLVReader & reader, T & value) + { + return reader.Get(value); + } + + CHIP_ERROR TlvGet(TLV::TLVReader & reader, chip_rpc_AttributeData_data_bytes_t & value) + { + value.size = reader.GetLength(); + return reader.GetBytes(value.bytes, sizeof(value.bytes)); + } + + template + CHIP_ERROR TlvGet(TLV::TLVReader & reader, char (&value)[N]) + { + return reader.GetString(value, N); + } + template ::pw::Status TlvBufferGetData(ByteSpan tlvBuffer, TLV::TLVType expectedDataType, T & responseData) { @@ -275,7 +432,7 @@ class Attributes : public pw_rpc::nanopb::Attributes::Service TLV::TLVReader dataReader; PW_TRY(ChipErrorToPwStatus(dataParser.GetData(&dataReader))); PW_TRY(CheckTlvTagAndType(&dataReader, TLV::ContextTag(0x2), expectedDataType)); - PW_TRY(ChipErrorToPwStatus(dataReader.Get(responseData))); + PW_TRY(ChipErrorToPwStatus(TlvGet(dataReader, responseData))); return ::pw::OkStatus(); } diff --git a/examples/platform/linux/system_rpc_server.cc b/examples/platform/linux/system_rpc_server.cc index b87a1c5d50bcc0..345845cfc3619c 100644 --- a/examples/platform/linux/system_rpc_server.cc +++ b/examples/platform/linux/system_rpc_server.cc @@ -42,6 +42,7 @@ uint16_t socket_port = 33000; stream::ServerSocket server_socket; stream::SocketStream socket_stream; +bool socket_stream_ready = false; hdlc::RpcChannelOutput hdlc_channel_output(socket_stream, hdlc::kDefaultRpcAddress, "HDLC channel"); Channel channels[] = { rpc::Channel::Create<1>(&hdlc_channel_output) }; @@ -57,10 +58,20 @@ void set_socket_port(uint16_t new_socket_port) void Init() { PW_LOG_INFO("Starting pw_rpc server on port %d", socket_port); - PW_CHECK_OK(server_socket.Listen(socket_port)); + Status status = server_socket.Listen(socket_port); + if (!status.ok()) + { + PW_LOG_ERROR("Listen failed. Initialization failed."); + return; + } auto accept_result = server_socket.Accept(); - PW_CHECK_OK(accept_result.status()); - socket_stream = *std::move(accept_result); + if (!accept_result.status().ok()) + { + PW_LOG_ERROR("Accept failed. Initialization failed."); + return; + } + socket_stream = *std::move(accept_result); + socket_stream_ready = true; } rpc::Server & Server() @@ -70,6 +81,11 @@ rpc::Server & Server() Status Start() { + if (!socket_stream_ready) + { + PW_LOG_ERROR("Socket failed to initialize. PWRPC start failed."); + return Status::FailedPrecondition(); + } // Declare a buffer for decoding incoming HDLC frames. std::array input_buffer; hdlc::Decoder decoder(input_buffer); From 47a95b9147ed3ade11446b0a23ec7eed94c9fa47 Mon Sep 17 00:00:00 2001 From: bhmanda-silabs <107180296+bhmanda-silabs@users.noreply.github.com> Date: Thu, 23 Jan 2025 21:27:41 +0530 Subject: [PATCH 14/40] [Silabs] Fixed the 917 NCP init (#37147) * Added fix for ncp init issue * Removed commented code * Removed unused variables * Resolved review comments * Reverted sl_board_configuration.h header include * Resolved review comments * Added latest sdk_support pointer and resolved review comments * Added comment for SPI transfer API * Disabled lcd and external flash in silabs_boards.gni for 917 NCP board * Added TODO for removing disabling lcd and enable external flash * TODO added properly in silabs_board.gni file --------- Co-authored-by: Andrei Litvin --- examples/platform/silabs/BaseApplication.cpp | 2 +- examples/platform/silabs/MatterConfig.cpp | 11 +- src/platform/silabs/PlatformManagerImpl.cpp | 4 +- .../silabs/wifi/SiWx/WifiInterfaceImpl.cpp | 13 -- .../silabs/wifi/SiWx/ncp/efx32_ncp_host.c | 201 ++++++------------ third_party/silabs/matter_support | 2 +- third_party/silabs/silabs_board.gni | 7 + 7 files changed, 88 insertions(+), 152 deletions(-) diff --git a/examples/platform/silabs/BaseApplication.cpp b/examples/platform/silabs/BaseApplication.cpp index a1e5e300178826..9b0cf784fb4428 100644 --- a/examples/platform/silabs/BaseApplication.cpp +++ b/examples/platform/silabs/BaseApplication.cpp @@ -184,7 +184,7 @@ void BaseApplicationDelegate::OnCommissioningSessionStopped() void BaseApplicationDelegate::OnCommissioningWindowClosed() { -#if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI917 +#if CHIP_CONFIG_ENABLE_ICD_SERVER && (defined(SLI_SI91X_MCU_INTERFACE) && SLI_SI91X_MCU_INTERFACE == 1) if (!BaseApplication::GetProvisionStatus() && !isComissioningStarted) { int32_t status = wfx_power_save(RSI_SLEEP_MODE_8, DEEP_SLEEP_WITH_RAM_RETENTION); diff --git a/examples/platform/silabs/MatterConfig.cpp b/examples/platform/silabs/MatterConfig.cpp index 0bacd0f6582f07..da3ca0dfab2855 100644 --- a/examples/platform/silabs/MatterConfig.cpp +++ b/examples/platform/silabs/MatterConfig.cpp @@ -46,10 +46,13 @@ #endif // TODO: We shouldn't need any platform specific includes in this file -#if defined(SLI_SI91X_MCU_INTERFACE) && SLI_SI91X_MCU_INTERFACE == 1 +#if (defined(SLI_SI91X_MCU_INTERFACE) && SLI_SI91X_MCU_INTERFACE == 1) #include +#endif // (defined(SLI_SI91X_MCU_INTERFACE) && SLI_SI91X_MCU_INTERFACE == 1 ) + +#if ((defined(SLI_SI91X_MCU_INTERFACE) && SLI_SI91X_MCU_INTERFACE == 1) || defined(EXP_BOARD)) #include -#endif // SLI_SI91X_MCU_INTERFACE +#endif // ((defined(SLI_SI91X_MCU_INTERFACE) && SLI_SI91X_MCU_INTERFACE == 1) || defined(EXP_BOARD)) #include // If building with the EFR32-provided crypto backend, we can use the @@ -321,9 +324,9 @@ CHIP_ERROR SilabsMatterConfig::InitWiFi(void) #endif // WF200_WIFI // TODO: Platform specific init should not be required here -#if defined(SLI_SI91X_MCU_INTERFACE) && SLI_SI91X_MCU_INTERFACE == 1 +#if ((defined(SLI_SI91X_MCU_INTERFACE) && SLI_SI91X_MCU_INTERFACE == 1) || defined(EXP_BOARD)) VerifyOrReturnError(InitSiWxWifi() == SL_STATUS_OK, CHIP_ERROR_INTERNAL); -#endif // SLI_SI91X_MCU_INTERFACE +#endif //((defined(SLI_SI91X_MCU_INTERFACE) && SLI_SI91X_MCU_INTERFACE == 1 ) || defined(EXP_BOARD)) return CHIP_NO_ERROR; } diff --git a/src/platform/silabs/PlatformManagerImpl.cpp b/src/platform/silabs/PlatformManagerImpl.cpp index 7b33b934b3664d..14026796eb05c4 100644 --- a/src/platform/silabs/PlatformManagerImpl.cpp +++ b/src/platform/silabs/PlatformManagerImpl.cpp @@ -84,10 +84,10 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) err = chip::DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init(); SuccessOrExit(err); -#if CHIP_SYSTEM_CONFIG_USE_LWIP && !defined(SLI_SI91X_MCU_INTERFACE) +#if CHIP_SYSTEM_CONFIG_USE_LWIP && !defined(SLI_SI91X_MCU_INTERFACE) && !defined(EXP_BOARD) // Initialize LwIP. tcpip_init(NULL, NULL); -#endif // CHIP_SYSTEM_CONFIG_USE_LWIP && !defined(SLI_SI91X_MCU_INTERFACE) +#endif // CHIP_SYSTEM_CONFIG_USE_LWIP && !defined(SLI_SI91X_MCU_INTERFACE) && !defined(EXP_BOARD) ReturnErrorOnFailure(System::Clock::InitClock_RealTime()); diff --git a/src/platform/silabs/wifi/SiWx/WifiInterfaceImpl.cpp b/src/platform/silabs/wifi/SiWx/WifiInterfaceImpl.cpp index 1477418ddd9412..00094dbb9a93bb 100644 --- a/src/platform/silabs/wifi/SiWx/WifiInterfaceImpl.cpp +++ b/src/platform/silabs/wifi/SiWx/WifiInterfaceImpl.cpp @@ -281,12 +281,6 @@ sl_status_t sl_wifi_siwx917_init(void) RSI_NPSSGPIO_InputBufferEn(RTE_UULP_GPIO_1_PIN, 1); #endif // ENABLE_CHIP_SHELL #endif // CHIP_CONFIG_ENABLE_ICD_SERVER - -#else - // NCP Configurations - status = InitSiWxWifi(); - VerifyOrReturnError(status == SL_STATUS_OK, status, - ChipLogError(DeviceLayer, "InitSiWxWifi failed: 0x%lx", static_cast(status))); #endif // SLI_SI91X_MCU_INTERFACE sl_wifi_firmware_version_t version = { 0 }; @@ -320,8 +314,6 @@ sl_status_t sl_wifi_siwx917_init(void) return status; } -// TODO: this changes will be reverted back after the Silabs WiFi SDK team fix the scan API -#ifndef EXP_BOARD sl_status_t ScanCallback(sl_wifi_event_t event, sl_wifi_scan_result_t * scan_result, uint32_t result_length, void * arg) { sl_status_t status = SL_STATUS_OK; @@ -346,17 +338,13 @@ sl_status_t ScanCallback(sl_wifi_event_t event, sl_wifi_scan_result_t * scan_res osSemaphoreRelease(sScanCompleteSemaphore); return status; } -#endif sl_status_t InitiateScan() { sl_status_t status = SL_STATUS_OK; -// TODO: this changes will be reverted back after the Silabs WiFi SDK team fix the scan API -#ifndef EXP_BOARD sl_wifi_ssid_t ssid = { 0 }; - // TODO: this changes will be reverted back after the Silabs WiFi SDK team fix the scan API sl_wifi_scan_configuration_t wifi_scan_configuration = default_wifi_scan_configuration; ssid.length = wfx_rsi.sec.ssid_length; @@ -376,7 +364,6 @@ sl_status_t InitiateScan() } osSemaphoreRelease(sScanInProgressSemaphore); -#endif return status; } diff --git a/src/platform/silabs/wifi/SiWx/ncp/efx32_ncp_host.c b/src/platform/silabs/wifi/SiWx/ncp/efx32_ncp_host.c index e5d0fb4a3a1dc2..a684c4ca063fab 100644 --- a/src/platform/silabs/wifi/SiWx/ncp/efx32_ncp_host.c +++ b/src/platform/silabs/wifi/SiWx/ncp/efx32_ncp_host.c @@ -27,8 +27,11 @@ #include "sl_si91x_host_interface.h" #include "sl_si91x_ncp_utility.h" #include "sl_si91x_status.h" +#include "sl_spidrv_exp_config.h" +#include "sl_spidrv_instances.h" #include "sl_status.h" #include "sl_wifi_constants.h" +#include "spidrv.h" #include #include #include @@ -42,35 +45,22 @@ #include "sl_board_control.h" #endif // SL_BOARD_NAME -static bool dma_callback(unsigned int channel, unsigned int sequenceNo, void * userParam); +#define LDMA_MAX_TRANSFER_LENGTH 4096 +#define LDMA_DESCRIPTOR_ARRAY_LENGTH (LDMA_MAX_TRANSFER_LENGTH / 2048) +#define SPI_HANDLE sl_spidrv_exp_handle +#define MAX_DATA_PACKET_SIZE 1800 + +// use SPI handle for EXP header (configured in project settings) +extern SPIDRV_Handle_t sl_spidrv_exp_handle; +static uint8_t dummy_buffer[MAX_DATA_PACKET_SIZE] = { 0 }; +static sl_si91x_host_init_configuration init_config = { 0 }; uint32_t rx_ldma_channel; uint32_t tx_ldma_channel; osMutexId_t ncp_transfer_mutex = 0; -static uint32_t dummy_buffer; -static sl_si91x_host_init_configuration init_config = { 0 }; - -// LDMA descriptor and transfer configuration structures for USART TX channel -LDMA_Descriptor_t ldmaTXDescriptor; -LDMA_TransferCfg_t ldmaTXConfig; - -// LDMA descriptor and transfer configuration structures for USART RX channel -LDMA_Descriptor_t ldmaRXDescriptor; -LDMA_TransferCfg_t ldmaRXConfig; - static osSemaphoreId_t transfer_done_semaphore = NULL; -static bool dma_callback([[maybe_unused]] unsigned int channel, [[maybe_unused]] unsigned int sequenceNo, - [[maybe_unused]] void * userParam) -{ -#if defined(SL_CATLOG_POWER_MANAGER_PRESENT) - sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1); -#endif - osSemaphoreRelease(transfer_done_semaphore); - return false; -} - static void gpio_interrupt([[maybe_unused]] uint8_t interrupt_number) { if (NULL != init_config.rx_irq) @@ -79,54 +69,27 @@ static void gpio_interrupt([[maybe_unused]] uint8_t interrupt_number) } } -static void efx32_spi_init(void) +static void spi_dma_callback(struct SPIDRV_HandleData * handle, Ecode_t transferStatus, int itemsTransferred) { - // Default asynchronous initializer (master mode, 1 Mbps, 8-bit data) - USART_InitSync_TypeDef init = USART_INITSYNC_DEFAULT; + UNUSED_PARAMETER(handle); + UNUSED_PARAMETER(transferStatus); + UNUSED_PARAMETER(itemsTransferred); +#if defined(SL_CATLOG_POWER_MANAGER_PRESENT) + sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1); +#endif + osSemaphoreRelease(transfer_done_semaphore); + return; +} - init.msbf = true; // MSB first transmission for SPI compatibility - init.autoCsEnable = false; - init.baudrate = USART_INITSYNC_BAUDRATE; +static void efx32_spi_init(void) +{ + SPIDRV_SetBitrate(SPI_HANDLE, USART_INITSYNC_BAUDRATE); // Configure SPI bus pins GPIO_PinModeSet(SPI_MISO_PIN.port, SPI_MISO_PIN.pin, gpioModeInput, 0); GPIO_PinModeSet(SPI_MOSI_PIN.port, SPI_MOSI_PIN.pin, gpioModePushPull, 0); GPIO_PinModeSet(SPI_CLOCK_PIN.port, SPI_CLOCK_PIN.pin, gpioModePushPullAlternate, 0); GPIO_PinModeSet(SPI_CS_PIN.port, SPI_CS_PIN.pin, gpioModePushPull, 1); - // Enable clock (not needed on xG21) - CMU_ClockEnable(SPI_USART_CMU_CLOCK, true); - - /* - * Route USART RX, TX, and CLK to the specified pins. Note that CS is - * not controlled by USART so there is no write to the corresponding - * USARTROUTE register to do this. - */ - GPIO->USARTROUTE[SPI_USART_ROUTE_INDEX].RXROUTE = - (SPI_MISO_PIN.port << _GPIO_USART_RXROUTE_PORT_SHIFT) | (SPI_MISO_PIN.pin << _GPIO_USART_RXROUTE_PIN_SHIFT); - GPIO->USARTROUTE[SPI_USART_ROUTE_INDEX].TXROUTE = - (SPI_MOSI_PIN.port << _GPIO_USART_TXROUTE_PORT_SHIFT) | (SPI_MOSI_PIN.pin << _GPIO_USART_TXROUTE_PIN_SHIFT); - GPIO->USARTROUTE[SPI_USART_ROUTE_INDEX].CLKROUTE = - (SPI_CLOCK_PIN.port << _GPIO_USART_CLKROUTE_PORT_SHIFT) | (SPI_CLOCK_PIN.pin << _GPIO_USART_CLKROUTE_PIN_SHIFT); - GPIO->USARTROUTE[SPI_USART_ROUTE_INDEX].CSROUTE = - (SPI_CS_PIN.port << _GPIO_USART_CSROUTE_PORT_SHIFT) | (SPI_CS_PIN.pin << _GPIO_USART_CSROUTE_PIN_SHIFT); - - // Enable USART interface pins - GPIO->USARTROUTE[SPI_USART_ROUTE_INDEX].ROUTEEN = GPIO_USART_ROUTEEN_RXPEN | // MISO - GPIO_USART_ROUTEEN_TXPEN | // MOSI -#if !SL_SPICTRL_MUX - GPIO_USART_ROUTEEN_CSPEN | -#endif - GPIO_USART_ROUTEEN_CLKPEN; - - // Set slew rate for alternate usage pins - GPIO_SlewrateSet(SPI_CLOCK_PIN.port, 7, 7); - - // Configure and enable USART - USART_InitSync(SPI_USART, &init); - - SPI_USART->TIMING |= USART_TIMING_TXDELAY_ONE | USART_TIMING_CSSETUP_ONE | USART_TIMING_CSHOLD_ONE; - - // SPI_USART->CTRL_SET |= USART_CTRL_SMSDELAY; // configure packet pending interrupt priority NVIC_SetPriority(GPIO_ODD_IRQn, PACKET_PENDING_INT_PRI); @@ -135,6 +98,46 @@ static void efx32_spi_init(void) GPIO_ExtIntConfig(INTERRUPT_PIN.port, INTERRUPT_PIN.pin, INTERRUPT_PIN.pin, true, false, true); } +Ecode_t si91x_SPIDRV_MTransfer(SPIDRV_Handle_t handle, const void * txBuffer, void * rxBuffer, int count, + SPIDRV_Callback_t callback) +{ + USART_TypeDef * usart = handle->initData.port; + uint8_t * tx = (txBuffer != NULL) ? (uint8_t *) txBuffer : dummy_buffer; + uint8_t * rx = (rxBuffer != NULL) ? (uint8_t *) rxBuffer : dummy_buffer; + + // For transfers less than 16 bytes, directly interacting with USART buffers is faster than using DMA + if (count < 16) + { + while (count > 0) + { + while (!(usart->STATUS & USART_STATUS_TXBL)) + { + } + usart->TXDATA = (uint32_t) *tx; + while (!(usart->STATUS & USART_STATUS_TXC)) + { + } + *rx = (uint8_t) usart->RXDATA; + if (txBuffer != NULL) + { + tx++; + } + if (rxBuffer != NULL) + { + rx++; + } + count--; + } + // callback(handle, ECODE_EMDRV_SPIDRV_OK, 0); + return ECODE_EMDRV_SPIDRV_OK; + } + else + { + SPIDRV_MTransfer(handle, tx, rx, count, callback); + } + return ECODE_EMDRV_SPIDRV_BUSY; +} + void sl_si91x_host_set_sleep_indicator(void) { GPIO_PinOutSet(SLEEP_CONFIRM_PIN.port, SLEEP_CONFIRM_PIN.pin); @@ -160,15 +163,16 @@ sl_status_t sl_si91x_host_init(const sl_si91x_host_init_configuration * config) return status; } #endif // SL_SPICTRL_MUX - init_config.rx_irq = config->rx_irq; - init_config.rx_done = config->rx_done; + init_config.rx_irq = config->rx_irq; + init_config.rx_done = config->rx_done; + init_config.boot_option = config->boot_option; // Enable clock (not needed on xG21) CMU_ClockEnable(cmuClock_GPIO, true); #if SL_SPICTRL_MUX spi_board_init(); -#endif +#endif // SL_SPICTRL_MUX if (transfer_done_semaphore == NULL) { @@ -189,10 +193,6 @@ sl_status_t sl_si91x_host_init(const sl_si91x_host_init_configuration * config) GPIO_PinModeSet(SLEEP_CONFIRM_PIN.port, SLEEP_CONFIRM_PIN.pin, gpioModeWiredOrPullDown, 1); GPIO_PinModeSet(WAKE_INDICATOR_PIN.port, WAKE_INDICATOR_PIN.pin, gpioModeWiredOrPullDown, 0); - DMADRV_Init(); - DMADRV_AllocateChannel((unsigned int *) &rx_ldma_channel, NULL); - DMADRV_AllocateChannel((unsigned int *) &tx_ldma_channel, NULL); - return SL_STATUS_OK; } @@ -223,68 +223,8 @@ sl_status_t sl_si91x_host_spi_transfer(const void * tx_buffer, void * rx_buffer, sl_wfx_host_spi_cs_assert(); #endif // SL_SPICTRL_MUX - if (buffer_length < 16) + if (ECODE_EMDRV_SPIDRV_BUSY == si91x_SPIDRV_MTransfer(SPI_HANDLE, tx_buffer, rx_buffer, buffer_length, spi_dma_callback)) { - uint8_t * tx = (tx_buffer != NULL) ? (uint8_t *) tx_buffer : (uint8_t *) &dummy_buffer; - uint8_t * rx = (rx_buffer != NULL) ? (uint8_t *) rx_buffer : (uint8_t *) &dummy_buffer; - while (buffer_length > 0) - { - while (!(SPI_USART->STATUS & USART_STATUS_TXBL)) - { - } - SPI_USART->TXDATA = (uint32_t) *tx; - while (!(SPI_USART->STATUS & USART_STATUS_TXC)) - { - } - *rx = (uint8_t) SPI_USART->RXDATA; - if (tx_buffer != NULL) - { - tx++; - } - if (rx_buffer != NULL) - { - rx++; - } - buffer_length--; - } - } - else - { - if (tx_buffer == NULL) - { - dummy_buffer = 0; - ldmaTXDescriptor = - (LDMA_Descriptor_t) LDMA_DESCRIPTOR_SINGLE_P2P_BYTE(&dummy_buffer, &(SPI_USART->TXDATA), buffer_length); - } - else - { - ldmaTXDescriptor = (LDMA_Descriptor_t) LDMA_DESCRIPTOR_SINGLE_M2P_BYTE(tx_buffer, &(SPI_USART->TXDATA), buffer_length); - } - - if (rx_buffer == NULL) - { - ldmaRXDescriptor = - (LDMA_Descriptor_t) LDMA_DESCRIPTOR_SINGLE_P2P_BYTE(&(SPI_USART->RXDATA), &dummy_buffer, buffer_length); - } - else - { - ldmaRXDescriptor = (LDMA_Descriptor_t) LDMA_DESCRIPTOR_SINGLE_P2M_BYTE(&(SPI_USART->RXDATA), rx_buffer, buffer_length); - } - - // Transfer a byte on free space in the USART buffer - ldmaTXConfig = (LDMA_TransferCfg_t) LDMA_TRANSFER_CFG_PERIPHERAL(SPI_USART_LDMA_TX); - - // Transfer a byte on receive data valid - ldmaRXConfig = (LDMA_TransferCfg_t) LDMA_TRANSFER_CFG_PERIPHERAL(SPI_USART_LDMA_RX); - -#if defined(SL_CATLOG_POWER_MANAGER_PRESENT) - sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1); -#endif - - // Start both channels - DMADRV_LdmaStartTransfer(rx_ldma_channel, &ldmaRXConfig, &ldmaRXDescriptor, dma_callback, NULL); - DMADRV_LdmaStartTransfer(tx_ldma_channel, &ldmaTXConfig, &ldmaTXDescriptor, NULL, NULL); - if (osSemaphoreAcquire(transfer_done_semaphore, 1000) != osOK) { BREAKPOINT(); @@ -300,7 +240,6 @@ sl_status_t sl_si91x_host_spi_transfer(const void * tx_buffer, void * rx_buffer, void sl_si91x_host_hold_in_reset(void) { - GPIO_PinModeSet(RESET_PIN.port, RESET_PIN.pin, gpioModePushPull, 1); GPIO_PinOutClear(RESET_PIN.port, RESET_PIN.pin); } diff --git a/third_party/silabs/matter_support b/third_party/silabs/matter_support index 8c594d45be3a3b..7ad2bdc6c2c100 160000 --- a/third_party/silabs/matter_support +++ b/third_party/silabs/matter_support @@ -1 +1 @@ -Subproject commit 8c594d45be3a3bc1bad4f3de0e3bfc16bd3cab56 +Subproject commit 7ad2bdc6c2c100ee6775b76b6cd055c40d29e117 diff --git a/third_party/silabs/silabs_board.gni b/third_party/silabs/silabs_board.gni index d013e967b61baf..6385a880a47ff6 100644 --- a/third_party/silabs/silabs_board.gni +++ b/third_party/silabs/silabs_board.gni @@ -69,6 +69,13 @@ declare_args() { chip_enable_ble_rs911x = use_rs9116 || use_SiWx917 } +# TODO - This needs to be removed once multiplexing issues resolved +if (use_SiWx917) { + disable_lcd = true + show_qr_code = false + use_external_flash = false +} + if (silabs_board == "") { silabs_board = getenv("SILABS_BOARD") } From 575a44018b84bb6cbc5e2aa1e9189152ef44f601 Mon Sep 17 00:00:00 2001 From: Amine Alami <43780877+Alami-Amine@users.noreply.github.com> Date: Thu, 23 Jan 2025 17:56:40 +0100 Subject: [PATCH 15/40] Silence CodeQL warning related to comparing uint8_t for loop index with a size_t pathsConfig.count (#37173) in reality pathsConfig.count will never exceed 255 but since this is TestCode simplest is to make the loop condition index a size_t --- .../tests/suites/commands/interaction_model/InteractionModel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/tests/suites/commands/interaction_model/InteractionModel.h b/src/app/tests/suites/commands/interaction_model/InteractionModel.h index 3acafb8de2acee..d8f166f39ed8fd 100644 --- a/src/app/tests/suites/commands/interaction_model/InteractionModel.h +++ b/src/app/tests/suites/commands/interaction_model/InteractionModel.h @@ -407,7 +407,7 @@ class InteractionModelWriter mTimedInteractionTimeoutMs, mSuppressResponse.ValueOr(false)); VerifyOrReturnError(mWriteClient != nullptr, CHIP_ERROR_NO_MEMORY); - for (uint8_t i = 0; i < pathsConfig.count; i++) + for (size_t i = 0; i < pathsConfig.count; i++) { auto & path = pathsConfig.attributePathParams[i]; auto & dataVersion = pathsConfig.dataVersionFilter[i].mDataVersion; From b2b62752a610d9ab0998665746d26580fc818ed2 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Thu, 23 Jan 2025 11:43:14 -0800 Subject: [PATCH 16/40] Consolidate basic assert tests (#37168) --- src/python_testing/TC_DGSW_2_1.py | 17 +-- src/python_testing/TC_DGSW_2_2.py | 17 +-- src/python_testing/TC_DGSW_2_3.py | 27 ++-- src/python_testing/TC_DGWIFI_2_1.py | 23 +-- .../chip/testing/matter_asserts.py | 131 ++++++++++++++---- .../chip/testing/matter_testing.py | 40 ------ .../chip/testing/test_matter_asserts.py | 125 +++++++++++++++++ 7 files changed, 271 insertions(+), 109 deletions(-) diff --git a/src/python_testing/TC_DGSW_2_1.py b/src/python_testing/TC_DGSW_2_1.py index 17ccef1b047436..86022bef0fd193 100644 --- a/src/python_testing/TC_DGSW_2_1.py +++ b/src/python_testing/TC_DGSW_2_1.py @@ -36,6 +36,7 @@ # import chip.clusters as Clusters +from chip.testing import matter_asserts from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main @@ -81,41 +82,41 @@ async def test_TC_DGSW_2_1(self): # Validate each element in the thread_metrics_list for metric in thread_metrics_list: # The Id field is mandatory - self.assert_valid_uint64(metric.id, "Id") + matter_asserts.assert_valid_uint64(metric.id, "Id") # Validate the optional Name field if metric.name is not None: - self.assert_valid_str(metric.name, "Name") + matter_asserts.assert_is_string(metric.name, "Name") # Validate the optional StackFreeCurrent field if metric.stackFreeCurrent is not None: - self.assert_valid_uint32(metric.stackFreeCurrent, "StackFreeCurrent") + matter_asserts.assert_valid_uint32(metric.stackFreeCurrent, "StackFreeCurrent") # Validate the optional StackFreeMinimum field if metric.stackFreeMinimum is not None: - self.assert_valid_uint32(metric.stackFreeMinimum, "StackFreeMinimum") + matter_asserts.assert_valid_uint32(metric.stackFreeMinimum, "StackFreeMinimum") # Validate the optional StackSize field if metric.stackSize is not None: - self.assert_valid_uint32(metric.stackSize, "StackSize") + matter_asserts.assert_valid_uint32(metric.stackSize, "StackSize") # STEP 3: TH reads from the DUT the CurrentHeapFree attribute self.step(3) if self.pics_guard(attributes.CurrentHeapFree.attribute_id in attribute_list): current_heap_free_attr = await self.read_dgsw_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentHeapFree) - self.assert_valid_uint64(current_heap_free_attr, "CurrentHeapFree") + matter_asserts.assert_valid_uint64(current_heap_free_attr, "CurrentHeapFree") # STEP 4: TH reads from the DUT the CurrentHeapUsed attribute self.step(4) if self.pics_guard(attributes.CurrentHeapUsed.attribute_id in attribute_list): current_heap_used_attr = await self.read_dgsw_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentHeapUsed) - self.assert_valid_uint64(current_heap_used_attr, "CurrentHeapUsed") + matter_asserts.assert_valid_uint64(current_heap_used_attr, "CurrentHeapUsed") # STEP 5: TH reads from the DUT the CurrentHeapHighWatermark attribute self.step(5) if self.pics_guard(attributes.CurrentHeapHighWatermark.attribute_id in attribute_list): current_heap_high_watermark_attr = await self.read_dgsw_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentHeapHighWatermark) - self.assert_valid_uint64(current_heap_high_watermark_attr, "CurrentHeapHighWatermark") + matter_asserts.assert_valid_uint64(current_heap_high_watermark_attr, "CurrentHeapHighWatermark") if __name__ == "__main__": diff --git a/src/python_testing/TC_DGSW_2_2.py b/src/python_testing/TC_DGSW_2_2.py index 03d4b0abc72443..1d93c9da8ab942 100644 --- a/src/python_testing/TC_DGSW_2_2.py +++ b/src/python_testing/TC_DGSW_2_2.py @@ -42,8 +42,8 @@ # import chip.clusters as Clusters +from chip.testing import matter_asserts from chip.testing.matter_testing import EventChangeCallback, MatterBaseTest, TestStep, async_test_body, default_matter_test_main -from mobly import asserts class TC_DGSW_2_2(MatterBaseTest): @@ -66,22 +66,13 @@ def validate_soft_fault_event_data(self, event_data): """ # Validate 'Id' field: Ensure it is a uint64 type - asserts.assert_true( - self.is_valid_uint_value(event_data.id, bit_count=64), - "The 'Id' field must be a uint64 type" - ) + matter_asserts.assert_valid_uint64(event_data.id, "Id") # Validate 'Name' field: Ensure it is a string - asserts.assert_true( - isinstance(event_data.name, str), - "The 'Name' field must be a string type" - ) + matter_asserts.assert_is_string(event_data.name, "Name") # Validate 'FaultRecording' field: Ensure it is an octet string (bytes or bytearray) - asserts.assert_true( - self.is_valid_octet_string(event_data.faultRecording), - "The 'FaultRecording' field must be an octet string (bytes or bytearray)" - ) + matter_asserts.assert_is_octstr(event_data.faultRecording, "FaultRecording") def desc_TC_DGSW_2_2(self) -> str: """Returns a description of this test""" diff --git a/src/python_testing/TC_DGSW_2_3.py b/src/python_testing/TC_DGSW_2_3.py index f713a563a54b6c..1daec5e2db6b24 100644 --- a/src/python_testing/TC_DGSW_2_3.py +++ b/src/python_testing/TC_DGSW_2_3.py @@ -38,6 +38,7 @@ import logging import chip.clusters as Clusters +from chip.testing import matter_asserts from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts @@ -94,31 +95,31 @@ async def test_TC_DGSW_2_3(self): # Iterate over all items in the list and validate each one for metric in thread_metrics_original: # The Id field is mandatory - self.assert_valid_uint64(metric.id, "Id") + matter_asserts.assert_valid_uint64(metric.id, "Id") if metric.name is not None: - self.assert_valid_str(metric.name, "Name") + matter_asserts.assert_is_string(metric.name, "Name") if metric.stackFreeCurrent is not None: - self.assert_valid_uint32(metric.stackFreeCurrent, "StackFreeCurrent") + matter_asserts.assert_valid_uint32(metric.stackFreeCurrent, "StackFreeCurrent") if metric.stackFreeMinimum is not None: - self.assert_valid_uint32(metric.stackFreeMinimum, "StackFreeMinimum") + matter_asserts.assert_valid_uint32(metric.stackFreeMinimum, "StackFreeMinimum") if metric.stackSize is not None: - self.assert_valid_uint32(metric.stackSize, "StackSize") + matter_asserts.assert_valid_uint32(metric.stackSize, "StackSize") # STEP 4: TH reads from the DUT the CurrentHeapHighWatermark attribute self.step(4) if self.pics_guard(attributes.CurrentHeapHighWatermark.attribute_id in attribute_list): high_watermark_original = await self.read_dgsw_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentHeapHighWatermark) - self.assert_valid_uint64(high_watermark_original, "CurrentHeapHighWatermark") + matter_asserts.assert_valid_uint64(high_watermark_original, "CurrentHeapHighWatermark") # STEP 5: TH reads from the DUT the CurrentHeapUsed attribute self.step(5) if self.pics_guard(attributes.CurrentHeapUsed.attribute_id in attribute_list): current_heap_used_original = await self.read_dgsw_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentHeapUsed) - self.assert_valid_uint64(current_heap_used_original, "CurrentHeapUsed") + matter_asserts.assert_valid_uint64(current_heap_used_original, "CurrentHeapUsed") if high_watermark_original is not None: asserts.assert_true(current_heap_used_original <= high_watermark_original, @@ -133,7 +134,7 @@ async def test_TC_DGSW_2_3(self): self.step(7) if self.pics_guard(attributes.CurrentHeapHighWatermark.attribute_id in attribute_list): current_heap_high_watermark = await self.read_dgsw_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentHeapHighWatermark) - self.assert_valid_uint64(current_heap_high_watermark, "CurrentHeapHighWatermark") + matter_asserts.assert_valid_uint64(current_heap_high_watermark, "CurrentHeapHighWatermark") # Verify that the returned value is <= high_watermark_original asserts.assert_true(current_heap_high_watermark <= high_watermark_original, @@ -152,19 +153,19 @@ async def test_TC_DGSW_2_3(self): # Validate all elements in the list for metric in thread_metrics_reset: - self.assert_valid_uint64(metric.id, "Id") + matter_asserts.assert_valid_uint64(metric.id, "Id") if metric.name is not None: - self.assert_valid_str(metric.name, "Name") + matter_asserts.assert_is_string(metric.name, "Name") if metric.stackFreeCurrent is not None: - self.assert_valid_uint32(metric.stackFreeCurrent, "StackFreeCurrent") + matter_asserts.assert_valid_uint32(metric.stackFreeCurrent, "StackFreeCurrent") if metric.stackFreeMinimum is not None: - self.assert_valid_uint32(metric.stackFreeMinimum, "StackFreeMinimum") + matter_asserts.assert_valid_uint32(metric.stackFreeMinimum, "StackFreeMinimum") if metric.stackSize is not None: - self.assert_valid_uint32(metric.stackSize, "StackSize") + matter_asserts.assert_valid_uint32(metric.stackSize, "StackSize") # Ensure the list length matches thread_metrics_original to simplify matching asserts.assert_equal(len(thread_metrics_reset), len(thread_metrics_original), diff --git a/src/python_testing/TC_DGWIFI_2_1.py b/src/python_testing/TC_DGWIFI_2_1.py index 707deb0198047f..2320385da0a763 100644 --- a/src/python_testing/TC_DGWIFI_2_1.py +++ b/src/python_testing/TC_DGWIFI_2_1.py @@ -34,6 +34,7 @@ import chip.clusters as Clusters from chip.clusters.Types import Nullable, NullValue +from chip.testing import matter_asserts from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts @@ -131,7 +132,7 @@ async def test_TC_DGWIFI_2_1(self): # Just do a minimal check here; you can refine or extend based on the spec. if security_type is not NullValue: security_type_value = security_type.Value - self.assert_valid_uint8(security_type_value, "SecurityType") + matter_asserts.assert_valid_uint8(security_type_value, "SecurityType") # Check if the security_type is a valid SecurityTypeEnum member self.assert_true( @@ -154,7 +155,7 @@ async def test_TC_DGWIFI_2_1(self): # WiFiVersion is an enum. If not configured or operational, might be NULL. if wifi_version is not NullValue: wifi_version_value = wifi_version.Value - self.assert_valid_uint8(wifi_version_value, "WiFiVersion") + matter_asserts.assert_valid_uint8(wifi_version_value, "WiFiVersion") # Check if the wifi_version is a valid WiFiVersionEnum member self.assert_true(wifi_version_value in [item.value for item in Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum], @@ -171,7 +172,7 @@ async def test_TC_DGWIFI_2_1(self): channel_number = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.ChannelNumber) # If not operational, might be NULL. Else we expect an unsigned integer channel. if channel_number is not NullValue: - self.assert_valid_uint16(channel_number.Value, "ChannelNumber") + matter_asserts.assert_valid_uint16(channel_number.Value, "ChannelNumber") # # STEP 6: TH reads RSSI attribute @@ -195,7 +196,7 @@ async def test_TC_DGWIFI_2_1(self): "BeaconLostCount must be of type 'Nullable' when not None.") if beacon_lost_count is not NullValue: - self.assert_valid_uint32(beacon_lost_count.Value, "BeaconLostCount") + matter_asserts.assert_valid_uint32(beacon_lost_count.Value, "BeaconLostCount") # # STEP 8: TH reads BeaconRxCount attribute @@ -207,7 +208,7 @@ async def test_TC_DGWIFI_2_1(self): "BeaconRxCount must be of type 'Nullable' when not None.") if beacon_rx_count is not NullValue: - self.assert_valid_uint32(beacon_rx_count.Value, "BeaconRxCount") + matter_asserts.assert_valid_uint32(beacon_rx_count.Value, "BeaconRxCount") # # STEP 9: TH reads PacketMulticastRxCount attribute @@ -219,7 +220,7 @@ async def test_TC_DGWIFI_2_1(self): "PacketMulticastRxCount must be of type 'Nullable' when not None.") if pkt_multi_rx is not NullValue: - self.assert_valid_uint32(pkt_multi_rx.Value, "PacketMulticastRxCount") + matter_asserts.assert_valid_uint32(pkt_multi_rx.Value, "PacketMulticastRxCount") # # STEP 10: TH reads PacketMulticastTxCount attribute @@ -231,7 +232,7 @@ async def test_TC_DGWIFI_2_1(self): "PacketMulticastTxCount must be of type 'Nullable' when not None.") if pkt_multi_tx is not NullValue: - self.assert_valid_uint32(pkt_multi_tx.Value, "PacketMulticastTxCount") + matter_asserts.assert_valid_uint32(pkt_multi_tx.Value, "PacketMulticastTxCount") # # STEP 11: TH reads PacketUnicastRxCount attribute @@ -243,7 +244,7 @@ async def test_TC_DGWIFI_2_1(self): "PacketUnicastRxCount must be of type 'Nullable' when not None.") if pkt_uni_rx is not NullValue: - self.assert_valid_uint32(pkt_uni_rx.Value, "PacketUnicastRxCount") + matter_asserts.assert_valid_uint32(pkt_uni_rx.Value, "PacketUnicastRxCount") # # STEP 12: TH reads PacketUnicastTxCount attribute @@ -255,7 +256,7 @@ async def test_TC_DGWIFI_2_1(self): "PacketUnicastTxCount must be of type 'Nullable' when not None.") if pkt_uni_tx is not NullValue: - self.assert_valid_uint32(pkt_uni_tx.Value, "PacketUnicastTxCount") + matter_asserts.assert_valid_uint32(pkt_uni_tx.Value, "PacketUnicastTxCount") # # STEP 13: TH reads CurrentMaxRate attribute @@ -268,7 +269,7 @@ async def test_TC_DGWIFI_2_1(self): "CurrentMaxRate must be of type 'Nullable' when not None.") if current_max_rate is not NullValue: - self.assert_valid_uint64(current_max_rate.Value, "CurrentMaxRate") + matter_asserts.assert_valid_uint64(current_max_rate.Value, "CurrentMaxRate") # # STEP 14: TH reads OverrunCount attribute @@ -281,7 +282,7 @@ async def test_TC_DGWIFI_2_1(self): "OverrunCount must be of type 'Nullable' when not None.") if overrun_count is not NullValue: - self.assert_valid_uint64(overrun_count.Value, "OverrunCount") + matter_asserts.assert_valid_uint64(overrun_count.Value, "OverrunCount") if __name__ == "__main__": diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_asserts.py b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_asserts.py index b7d6fca4a9eccd..4b17612d7e24cf 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_asserts.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_asserts.py @@ -8,39 +8,102 @@ T = TypeVar('T') + +# Internal helper functions + +def is_valid_uint_value(value: Any, bit_count: int = 64) -> bool: + """ + Checks if 'value' is a non-negative integer that fits into 'bit_count' bits. + For example, bit_count=32 => 0 <= value <= 0xFFFFFFFF + """ + if not isinstance(value, int): + return False + if value < 0: + return False + return value < (1 << bit_count) + + +def is_valid_int_value(value: Any, bit_count: int = 8) -> bool: + """ + Checks if 'value' is a signed integer that fits into 'bit_count' bits. + For example, for int8: -128 <= value <= 127. + """ + min_val = -(1 << (bit_count - 1)) + max_val = (1 << (bit_count - 1)) - 1 + return isinstance(value, int) and (min_val <= value <= max_val) + + +def is_valid_bool_value(value: Any) -> bool: + """ + Checks if 'value' is a boolean. + """ + return isinstance(value, bool) + + # Integer assertions +def assert_valid_uint64(value: Any, description: str) -> None: + """ + Asserts that the value is a valid uint64 (0 <= value < 2^64). + """ + asserts.assert_true(is_valid_uint_value(value, bit_count=64), + f"{description} must be a valid uint64 integer") + def assert_valid_uint32(value: Any, description: str) -> None: """ - Asserts that the value is a valid uint32. + Asserts that the value is a valid uint32 (0 <= value < 2^32). + """ + asserts.assert_true(is_valid_uint_value(value, bit_count=32), + f"{description} must be a valid uint32 integer") - Args: - value: The value to check - description: User-defined description for error messages - Raises: - AssertionError: If value is not an integer or outside the uint32 range (0 to 0xFFFFFFFF) +def assert_valid_uint16(value: Any, description: str) -> None: """ - asserts.assert_true(isinstance(value, int), f"{description} must be an integer") - asserts.assert_greater_equal(value, 0, f"{description} must be non-negative") - asserts.assert_less_equal(value, 0xFFFFFFFF, f"{description} must not exceed 0xFFFFFFFF") + Asserts that the value is a valid uint16 (0 <= value < 2^16). + """ + asserts.assert_true(is_valid_uint_value(value, bit_count=16), + f"{description} must be a valid uint16 integer") -def assert_valid_uint64(value: Any, description: str) -> None: +def assert_valid_uint8(value: Any, description: str) -> None: """ - Asserts that the value is a valid uint64. + Asserts that the value is a valid uint8 (0 <= value < 2^8). + """ + asserts.assert_true(is_valid_uint_value(value, bit_count=8), + f"{description} must be a valid uint8 integer") - Args: - value: The value to check - description: User-defined description for error messages - Raises: - AssertionError: If value is not an integer or outside the uint64 range (0 to 0xFFFFFFFFFFFFFFFF) +def assert_valid_int64(value: Any, description: str) -> None: """ - asserts.assert_true(isinstance(value, int), f"{description} must be an integer") - asserts.assert_greater_equal(value, 0, f"{description} must be non-negative") - asserts.assert_less_equal(value, 0xFFFFFFFFFFFFFFFF, f"{description} must not exceed 0xFFFFFFFFFFFFFFFF") + Asserts that the value is a valid int64 (-2^63 <= value <= 2^63-1). + """ + asserts.assert_true(is_valid_int_value(value, bit_count=64), + f"{description} must be a valid int64 integer") + + +def assert_valid_int32(value: Any, description: str) -> None: + """ + Asserts that the value is a valid int32 (-2^31 <= value <= 2^31-1). + """ + asserts.assert_true(is_valid_int_value(value, bit_count=32), + f"{description} must be a valid int32 integer") + + +def assert_valid_int16(value: Any, description: str) -> None: + """ + Asserts that the value is a valid int16 (-2^15 <= value <= 2^15-1). + """ + asserts.assert_true(is_valid_int_value(value, bit_count=16), + f"{description} must be a valid int16 integer") + + +def assert_valid_int8(value: Any, description: str) -> None: + """ + Asserts that the value is a valid int8 (-128 <= value <= 127). + """ + asserts.assert_true(is_valid_int_value(value, bit_count=8), + f"{description} must be a valid int8 integer") def assert_int_in_range(value: Any, min_value: int, max_value: int, description: str) -> None: @@ -60,8 +123,8 @@ def assert_int_in_range(value: Any, min_value: int, max_value: int, description: asserts.assert_greater_equal(value, min_value, f"{description} must be greater than or equal to {min_value}") asserts.assert_less_equal(value, max_value, f"{description} must be less than or equal to {max_value}") -# List assertions +# List assertions def assert_list(value: Any, description: str, min_length: Optional[int] = None, max_length: Optional[int] = None) -> None: """ @@ -104,8 +167,8 @@ def assert_list_element_type(value: List[Any], description: str, expected_type: asserts.assert_true(isinstance(item, expected_type), f"{description}[{i}] must be of type {expected_type.__name__}") -# String assertions +# String assertions def assert_is_string(value: Any, description: str) -> None: """ @@ -139,11 +202,9 @@ def assert_string_length(value: Any, description: str, min_length: Optional[int] - Use min_length=None, max_length=None to only validate string type (same as assert_is_string) """ assert_is_string(value, description) - if min_length is not None: asserts.assert_greater_equal(len(value), min_length, f"{description} length must be at least {min_length} characters") - if max_length is not None: asserts.assert_less_equal(len(value), max_length, f"{description} length must not exceed {max_length} characters") @@ -162,8 +223,22 @@ def assert_non_empty_string(value: Any, description: str) -> None: """ assert_string_length(value, description, min_length=1) -# Matter-specific assertions +def assert_is_octstr(value: Any, description: str) -> None: + """ + Asserts that the value is a octet string. + + Args: + value: The value to check + description: User-defined description for error messages + + Raises: + AssertionError: If value is not a octet string (bytes) + """ + asserts.assert_true(isinstance(value, bytes), f"{description} must be a octet string (bytes)") + + +# Matter-specific assertions def assert_string_matches_pattern(value: str, description: str, pattern: str) -> None: """ @@ -243,3 +318,11 @@ def assert_standard_command_id(id: int) -> None: from chip.testing.global_attribute_ids import is_standard_command_id asserts.assert_true(is_standard_command_id(id), f"Not a standard command ID: {hex(id)}") + + +def assert_valid_enum(value: Any, description: str, enum_type: type) -> None: + """ + Asserts that 'value' is a valid instance of the specified enum type. + """ + asserts.assert_true(isinstance(value, enum_type), + f"{description} must be of type {enum_type.__name__}") diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py index 799b950882142a..1054463ea64489 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/matter_testing.py @@ -972,46 +972,6 @@ def __init__(self, *args): # The named pipe name must be set in the derived classes self.app_pipe = None - @staticmethod - def is_valid_uint_value(value, bit_count=64): - """ - Checks if 'value' is a non-negative integer fitting into 'bit_count' bits. - For example, bit_count=32 => must fit within 0 <= value <= 0xFFFFFFFF - """ - if not isinstance(value, int): - return False - if value < 0: - return False - return value < 2**bit_count - - @staticmethod - def is_valid_str_value(value): - return isinstance(value, str) and len(value) > 0 - - def assert_valid_uint64(self, value, field_name): - """Asserts that the value is a valid uint64.""" - asserts.assert_true(self.is_valid_uint_value(value, bit_count=64), - f"{field_name} should be a uint64 or NULL.") - - def assert_valid_uint32(self, value, field_name): - """Asserts that the value is a valid uint32.""" - asserts.assert_true(self.is_valid_uint_value(value, bit_count=32), - f"{field_name} should be a uint32 or NULL.") - - def assert_valid_uint16(self, value, field_name): - """Asserts that the value is a valid uint16.""" - asserts.assert_true(self.is_valid_uint_value(value, bit_count=16), - f"{field_name} should be a uint16 or NULL.") - - def assert_valid_uint8(self, value, field_name): - """Asserts that the value is a valid uint16.""" - asserts.assert_true(self.is_valid_uint_value(value, bit_count=8), - f"{field_name} should be a uint8 or NULL.") - - def assert_valid_str(self, value, field_name): - """Asserts that the value is a non-empty string.""" - asserts.assert_true(self.is_valid_str_value(value), f"{field_name} field should be a non-empty string") - def get_test_steps(self, test: str) -> list[TestStep]: ''' Retrieves the test step list for the given test diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/test_matter_asserts.py b/src/python_testing/matter_testing_infrastructure/chip/testing/test_matter_asserts.py index 2b1c55d629f1f7..88df62ffdad721 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/test_matter_asserts.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/test_matter_asserts.py @@ -1,11 +1,17 @@ """Unit tests for matter_asserts module.""" +import enum import unittest from chip.testing import matter_asserts from mobly import signals +class MyTestEnum(enum.Enum): + VALID_MEMBER = 1 + ANOTHER_MEMBER = 2 + + class TestMatterAsserts(unittest.TestCase): """Unit tests for matter_asserts module.""" @@ -42,6 +48,90 @@ def test_assert_valid_uint64(self): with self.assertRaises(signals.TestFailure): matter_asserts.assert_valid_uint64(42.0, "test_float") + def test_assert_valid_uint16(self): + """Test assert_valid_uint16 with valid and invalid values.""" + # Valid cases + matter_asserts.assert_valid_uint16(0, "test_min") + matter_asserts.assert_valid_uint16(0xFFFF, "test_max") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_uint16(-1, "test_negative") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_uint16(0x10000, "test_too_large") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_uint16("42", "test_string") + + def test_assert_valid_uint8(self): + """Test assert_valid_uint8 with valid and invalid values.""" + # Valid cases + matter_asserts.assert_valid_uint8(0, "test_min") + matter_asserts.assert_valid_uint8(0xFF, "test_max") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_uint8(-1, "test_negative") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_uint8(0x100, "test_too_large") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_uint8("42", "test_string") + + def test_assert_valid_int64(self): + """Test assert_valid_int64 with valid and invalid values.""" + # Valid cases + matter_asserts.assert_valid_int64(-2**63, "test_min") + matter_asserts.assert_valid_int64(2**63 - 1, "test_max") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int64(-2**63 - 1, "test_too_small") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int64(2**63, "test_too_large") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int64("42", "test_string") + + def test_assert_valid_int32(self): + """Test assert_valid_int32 with valid and invalid values.""" + # Valid cases + matter_asserts.assert_valid_int32(-2**31, "test_min") + matter_asserts.assert_valid_int32(2**31 - 1, "test_max") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int32(-2**31 - 1, "test_too_small") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int32(2**31, "test_too_large") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int32("42", "test_string") + + def test_assert_valid_int16(self): + """Test assert_valid_int16 with valid and invalid values.""" + # Valid cases + matter_asserts.assert_valid_int16(-2**15, "test_min") + matter_asserts.assert_valid_int16(2**15 - 1, "test_max") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int16(-2**15 - 1, "test_too_small") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int16(2**15, "test_too_large") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int16("42", "test_string") + + def test_assert_valid_int8(self): + """Test assert_valid_int8 with valid and invalid values.""" + # Valid cases + matter_asserts.assert_valid_int8(-128, "test_min") + matter_asserts.assert_valid_int8(127, "test_max") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int8(-129, "test_too_small") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int8(128, "test_too_large") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_int8("42", "test_string") + def test_assert_int_in_range(self): """Test assert_int_in_range with valid and invalid values.""" # Valid cases @@ -126,6 +216,41 @@ def test_assert_non_empty_string(self): with self.assertRaises(signals.TestFailure): matter_asserts.assert_non_empty_string(42, "test_not_string") + def test_assert_is_octstr(self): + """Test assert_is_octstr with valid and invalid values.""" + # Valid case + matter_asserts.assert_is_octstr(b"", "test_empty_bytes") + matter_asserts.assert_is_octstr(b"\x01\x02", "test_some_bytes") + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_is_octstr("not_bytes", "test_string") + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_is_octstr(123, "test_int") + + def test_assert_string_matches_pattern(self): + """Test assert_string_matches_pattern with valid and invalid values.""" + # Valid cases + matter_asserts.assert_string_matches_pattern("abc123", "test_alphanumeric", r'^[a-z0-9]+$') + matter_asserts.assert_string_matches_pattern("hello", "test_hello", r'^hello$') + + # Invalid cases + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_string_matches_pattern(123, "test_not_string", r'^.*$') + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_string_matches_pattern("abc!", "test_pattern_mismatch", r'^[a-z0-9]+$') + + def test_assert_valid_enum(self): + """Test assert_valid_enum with valid and invalid values.""" + # Valid case + matter_asserts.assert_valid_enum(MyTestEnum.VALID_MEMBER, "test_enum_member", MyTestEnum) + + # Invalid cases: not an enum member or wrong type + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_enum(1, "test_int_instead_of_enum", MyTestEnum) + with self.assertRaises(signals.TestFailure): + matter_asserts.assert_valid_enum("INVALID", "test_string", MyTestEnum) + # Matter-specific assertion tests def test_assert_valid_attribute_id(self): """Test assert_valid_attribute_id with valid and invalid values.""" From 43f37d1f30851b3bea220e5d83f9b7d3a1f9f3d2 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Thu, 23 Jan 2025 15:40:42 -0500 Subject: [PATCH 17/40] Update metadata-tree from `MetadaList Foo(path)` to `CHIP_ERROR Foo(path, ListBuilder &)` (#37127) * Append-only API update: use CHIP_ERROR and builders for MetadataTree * Fix includes * Remove odd comment * ScopedSpan == ReadOnlyBuffer and Build == TakeBuffer * Update src/app/InteractionModelEngine.cpp Co-authored-by: Tennessee Carmel-Veilleux * Update src/app/clusters/descriptor/descriptor.cpp Co-authored-by: Tennessee Carmel-Veilleux * Update src/app/clusters/descriptor/descriptor.cpp Co-authored-by: Tennessee Carmel-Veilleux * Update src/app/clusters/descriptor/descriptor.cpp Co-authored-by: Tennessee Carmel-Veilleux * Update src/app/clusters/descriptor/descriptor.cpp Co-authored-by: Tennessee Carmel-Veilleux * Update src/app/clusters/descriptor/descriptor.cpp Co-authored-by: Tennessee Carmel-Veilleux * Update src/app/data-model-provider/MetadataList.cpp Co-authored-by: Tennessee Carmel-Veilleux * Replaced a lot of auto with const auto for readability * Update src/app/clusters/microwave-oven-control-server/microwave-oven-control-server.cpp Co-authored-by: Tennessee Carmel-Veilleux * Remove old comment * Fix some typos * Fix typo * Update src/app/data-model-provider/MetadataTypes.h Co-authored-by: Junior Martinez <67972863+jmartinez-silabs@users.noreply.github.com> --------- Co-authored-by: Tennessee Carmel-Veilleux Co-authored-by: Junior Martinez <67972863+jmartinez-silabs@users.noreply.github.com> Co-authored-by: Andrei Litvin --- src/access/ProviderDeviceTypeResolver.h | 7 +- src/app/AttributePathExpandIterator.cpp | 23 +- src/app/AttributePathExpandIterator.h | 6 +- src/app/InteractionModelEngine.cpp | 13 +- src/app/clusters/descriptor/descriptor.cpp | 80 +-- .../microwave-oven-control-server.cpp | 21 +- src/app/data-model-provider/BUILD.gn | 1 + src/app/data-model-provider/MetadataList.cpp | 185 ++++--- src/app/data-model-provider/MetadataList.h | 184 ++++--- .../data-model-provider/MetadataLookup.cpp | 22 +- src/app/data-model-provider/MetadataLookup.h | 15 +- src/app/data-model-provider/MetadataTypes.cpp | 51 ++ src/app/data-model-provider/MetadataTypes.h | 22 +- .../tests/TestMetadataList.cpp | 361 ++++--------- .../codegen/CodegenDataModelProvider.cpp | 486 ++++++------------ .../codegen/CodegenDataModelProvider.h | 18 +- .../tests/TestCodegenModelViaMocks.cpp | 183 +++++-- 17 files changed, 787 insertions(+), 891 deletions(-) create mode 100644 src/app/data-model-provider/MetadataTypes.cpp diff --git a/src/access/ProviderDeviceTypeResolver.h b/src/access/ProviderDeviceTypeResolver.h index 404c0cfa56c1af..aff5b424a693f1 100644 --- a/src/access/ProviderDeviceTypeResolver.h +++ b/src/access/ProviderDeviceTypeResolver.h @@ -16,6 +16,8 @@ #pragma once #include +#include +#include #include namespace chip { @@ -31,8 +33,9 @@ class DynamicProviderDeviceTypeResolver : public chip::Access::AccessControl::De bool IsDeviceTypeOnEndpoint(chip::DeviceTypeId deviceType, chip::EndpointId endpoint) override { - auto deviceTypes = mModelGetter()->DeviceTypes(endpoint); - for (auto & type : deviceTypes.GetSpanValidForLifetime()) + app::DataModel::ListBuilder builder; + (void) mModelGetter()->DeviceTypes(endpoint, builder); + for (auto & type : builder.TakeBuffer()) { if (type.deviceTypeId == deviceType) { diff --git a/src/app/AttributePathExpandIterator.cpp b/src/app/AttributePathExpandIterator.cpp index bd8e3e018b0155..7f357164427b44 100644 --- a/src/app/AttributePathExpandIterator.cpp +++ b/src/app/AttributePathExpandIterator.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -139,13 +140,13 @@ std::optional AttributePathExpandIterator::NextAttributeId() if (mAttributeIndex == kInvalidIndex) { // start a new iteration of attributes on the current cluster path. - mAttributes = mDataModelProvider->Attributes(mPosition.mOutputPath); + mAttributes = mDataModelProvider->AttributesIgnoreError(mPosition.mOutputPath); if (mPosition.mOutputPath.mAttributeId != kInvalidAttributeId) { // Position on the correct attribute if we have a start point mAttributeIndex = 0; - while ((mAttributeIndex < mAttributes.Size()) && + while ((mAttributeIndex < mAttributes.size()) && (mAttributes[mAttributeIndex].attributeId != mPosition.mOutputPath.mAttributeId)) { mAttributeIndex++; @@ -199,7 +200,7 @@ std::optional AttributePathExpandIterator::NextAttributeId() return std::nullopt; } - if (mAttributeIndex < mAttributes.Size()) + if (mAttributeIndex < mAttributes.size()) { return mAttributes[mAttributeIndex].attributeId; } @@ -222,13 +223,13 @@ std::optional AttributePathExpandIterator::NextClusterId() if (mClusterIndex == kInvalidIndex) { // start a new iteration on the current endpoint - mClusters = mDataModelProvider->ServerClusters(mPosition.mOutputPath.mEndpointId); + mClusters = mDataModelProvider->ServerClustersIgnoreError(mPosition.mOutputPath.mEndpointId); if (mPosition.mOutputPath.mClusterId != kInvalidClusterId) { // Position on the correct cluster if we have a start point mClusterIndex = 0; - while ((mClusterIndex < mClusters.Size()) && (mClusters[mClusterIndex].clusterId != mPosition.mOutputPath.mClusterId)) + while ((mClusterIndex < mClusters.size()) && (mClusters[mClusterIndex].clusterId != mPosition.mOutputPath.mClusterId)) { mClusterIndex++; } @@ -248,10 +249,8 @@ std::optional AttributePathExpandIterator::NextClusterId() { const ClusterId clusterId = mPosition.mAttributePath->mValue.mClusterId; - auto span = mClusters.GetSpanValidForLifetime(); - bool found = false; - for (auto & entry : span) + for (auto & entry : mClusters) { if (entry.clusterId == clusterId) { @@ -276,7 +275,7 @@ std::optional AttributePathExpandIterator::NextClusterId() } VerifyOrReturnValue(mPosition.mAttributePath->mValue.HasWildcardClusterId(), std::nullopt); - VerifyOrReturnValue(mClusterIndex < mClusters.Size(), std::nullopt); + VerifyOrReturnValue(mClusterIndex < mClusters.size(), std::nullopt); return mClusters[mClusterIndex].clusterId; } @@ -286,13 +285,13 @@ std::optional AttributePathExpandIterator::NextEndpointId() if (mEndpointIndex == kInvalidIndex) { // index is missing, have to start a new iteration - mEndpoints = mDataModelProvider->Endpoints(); + mEndpoints = mDataModelProvider->EndpointsIgnoreError(); if (mPosition.mOutputPath.mEndpointId != kInvalidEndpointId) { // Position on the correct endpoint if we have a start point mEndpointIndex = 0; - while ((mEndpointIndex < mEndpoints.Size()) && (mEndpoints[mEndpointIndex].id != mPosition.mOutputPath.mEndpointId)) + while ((mEndpointIndex < mEndpoints.size()) && (mEndpoints[mEndpointIndex].id != mPosition.mOutputPath.mEndpointId)) { mEndpointIndex++; } @@ -315,7 +314,7 @@ std::optional AttributePathExpandIterator::NextEndpointId() } VerifyOrReturnValue(mPosition.mAttributePath->mValue.HasWildcardEndpointId(), std::nullopt); - VerifyOrReturnValue(mEndpointIndex < mEndpoints.Size(), std::nullopt); + VerifyOrReturnValue(mEndpointIndex < mEndpoints.size(), std::nullopt); return mEndpoints[mEndpointIndex].id; } diff --git a/src/app/AttributePathExpandIterator.h b/src/app/AttributePathExpandIterator.h index 75993d80ae5297..e5d1f961434eb2 100644 --- a/src/app/AttributePathExpandIterator.h +++ b/src/app/AttributePathExpandIterator.h @@ -121,13 +121,13 @@ class AttributePathExpandIterator DataModel::Provider * mDataModelProvider; Position & mPosition; - DataModel::MetadataList mEndpoints; // all endpoints + DataModel::ReadOnlyBuffer mEndpoints; // all endpoints size_t mEndpointIndex = kInvalidIndex; - DataModel::MetadataList mClusters; // all clusters ON THE CURRENT endpoint + DataModel::ReadOnlyBuffer mClusters; // all clusters ON THE CURRENT endpoint size_t mClusterIndex = kInvalidIndex; - DataModel::MetadataList mAttributes; // all attributes ON THE CURRENT cluster + DataModel::ReadOnlyBuffer mAttributes; // all attributes ON THE CURRENT cluster size_t mAttributeIndex = kInvalidIndex; /// Move to the next endpoint/cluster/attribute triplet that is valid given diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp index 325c0dd416ec80..ec999d3cc53a31 100644 --- a/src/app/InteractionModelEngine.cpp +++ b/src/app/InteractionModelEngine.cpp @@ -37,9 +37,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -91,8 +93,7 @@ bool MayHaveAccessibleEventPathForEndpoint(DataModel::Provider * aProvider, Endp aSubjectDescriptor); } - auto serverClusters = aProvider->ServerClusters(aEventPath.mEndpointId); - for (auto & cluster : serverClusters.GetSpanValidForLifetime()) + for (auto & cluster : aProvider->ServerClustersIgnoreError(aEventPath.mEndpointId)) { if (MayHaveAccessibleEventPathForEndpointAndCluster(ConcreteClusterPath(aEventPath.mEndpointId, cluster.clusterId), aEventPath, aSubjectDescriptor)) @@ -114,8 +115,7 @@ bool MayHaveAccessibleEventPath(DataModel::Provider * aProvider, const EventPath return MayHaveAccessibleEventPathForEndpoint(aProvider, aEventPath.mEndpointId, aEventPath, subjectDescriptor); } - auto endpoints = aProvider->Endpoints(); - for (const DataModel::EndpointEntry & ep : endpoints.GetSpanValidForLifetime()) + for (const DataModel::EndpointEntry & ep : aProvider->EndpointsIgnoreError()) { if (MayHaveAccessibleEventPathForEndpoint(aProvider, ep.id, aEventPath, subjectDescriptor)) { @@ -1790,8 +1790,9 @@ Protocols::InteractionModel::Status InteractionModelEngine::CheckCommandExistenc { auto provider = GetDataModelProvider(); - DataModel::MetadataList acceptedCommands = provider->AcceptedCommands(aCommandPath); - for (auto & existing : acceptedCommands.GetSpanValidForLifetime()) + DataModel::ListBuilder acceptedCommands; + (void) provider->AcceptedCommands(aCommandPath, acceptedCommands); + for (auto & existing : acceptedCommands.TakeBuffer()) { if (existing.commandId == aCommandPath.mCommandId) { diff --git a/src/app/clusters/descriptor/descriptor.cpp b/src/app/clusters/descriptor/descriptor.cpp index ecc93d4a77267a..35ddcabfd428d2 100644 --- a/src/app/clusters/descriptor/descriptor.cpp +++ b/src/app/clusters/descriptor/descriptor.cpp @@ -23,7 +23,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -60,7 +62,7 @@ bool IsDescendantOf(const DataModel::EndpointEntry * __restrict__ childEndpoint, childEndpoint = nullptr; // we will look it up again // find the requested value in the array to get its parent - for (auto & ep : allEndpoints) + for (const auto & ep : allEndpoints) { if (ep.id == lookupId) { @@ -83,7 +85,8 @@ class DescriptorAttrAccess : public AttributeAccessInterface CHIP_ERROR ReadTagListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); CHIP_ERROR ReadPartsAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); CHIP_ERROR ReadDeviceAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadClientServerAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder, bool server); + CHIP_ERROR ReadClientClusters(EndpointId endpoint, AttributeValueEncoder & aEncoder); + CHIP_ERROR ReadServerClusters(EndpointId endpoint, AttributeValueEncoder & aEncoder); CHIP_ERROR ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder); CHIP_ERROR ReadFeatureMap(EndpointId endpoint, AttributeValueEncoder & aEncoder); }; @@ -103,9 +106,11 @@ CHIP_ERROR DescriptorAttrAccess::ReadFeatureMap(EndpointId endpoint, AttributeVa CHIP_ERROR DescriptorAttrAccess::ReadTagListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) { - return aEncoder.EncodeList([&endpoint](const auto & encoder) -> CHIP_ERROR { - auto tags = InteractionModelEngine::GetInstance()->GetDataModelProvider()->SemanticTags(endpoint); - for (auto & tag : tags.GetSpanValidForLifetime()) + DataModel::ListBuilder semanticTagsList; + ReturnErrorOnFailure(InteractionModelEngine::GetInstance()->GetDataModelProvider()->SemanticTags(endpoint, semanticTagsList)); + + return aEncoder.EncodeList([&semanticTagsList](const auto & encoder) -> CHIP_ERROR { + for (const auto & tag : semanticTagsList.TakeBuffer()) { ReturnErrorOnFailure(encoder.Encode(tag)); } @@ -115,11 +120,13 @@ CHIP_ERROR DescriptorAttrAccess::ReadTagListAttribute(EndpointId endpoint, Attri CHIP_ERROR DescriptorAttrAccess::ReadPartsAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) { - auto endpoints = InteractionModelEngine::GetInstance()->GetDataModelProvider()->Endpoints(); + DataModel::ListBuilder endpointsList; + ReturnErrorOnFailure(InteractionModelEngine::GetInstance()->GetDataModelProvider()->Endpoints(endpointsList)); + auto endpoints = endpointsList.TakeBuffer(); if (endpoint == 0x00) { return aEncoder.EncodeList([&endpoints](const auto & encoder) -> CHIP_ERROR { - for (auto & ep : endpoints.GetSpanValidForLifetime()) + for (const auto & ep : endpoints) { if (ep.id == 0) { @@ -133,7 +140,7 @@ CHIP_ERROR DescriptorAttrAccess::ReadPartsAttribute(EndpointId endpoint, Attribu // find the given endpoint unsigned idx = 0; - while (idx < endpoints.Size()) + while (idx < endpoints.size()) { if (endpoints[idx].id == endpoint) { @@ -141,7 +148,7 @@ CHIP_ERROR DescriptorAttrAccess::ReadPartsAttribute(EndpointId endpoint, Attribu } idx++; } - if (idx >= endpoints.Size()) + if (idx >= endpoints.size()) { // not found return CHIP_ERROR_NOT_FOUND; @@ -154,9 +161,9 @@ CHIP_ERROR DescriptorAttrAccess::ReadPartsAttribute(EndpointId endpoint, Attribu case DataModel::EndpointCompositionPattern::kFullFamily: // encodes ALL endpoints that have the specified endpoint as a descendant return aEncoder.EncodeList([&endpoints, endpoint](const auto & encoder) -> CHIP_ERROR { - for (auto & ep : endpoints.GetSpanValidForLifetime()) + for (const auto & ep : endpoints) { - if (IsDescendantOf(&ep, endpoint, endpoints.GetSpanValidForLifetime())) + if (IsDescendantOf(&ep, endpoint, endpoints)) { ReturnErrorOnFailure(encoder.Encode(ep.id)); } @@ -166,7 +173,7 @@ CHIP_ERROR DescriptorAttrAccess::ReadPartsAttribute(EndpointId endpoint, Attribu case DataModel::EndpointCompositionPattern::kTree: return aEncoder.EncodeList([&endpoints, endpoint](const auto & encoder) -> CHIP_ERROR { - for (auto & ep : endpoints.GetSpanValidForLifetime()) + for (const auto & ep : endpoints) { if (ep.parentId != endpoint) { @@ -184,11 +191,14 @@ CHIP_ERROR DescriptorAttrAccess::ReadPartsAttribute(EndpointId endpoint, Attribu CHIP_ERROR DescriptorAttrAccess::ReadDeviceAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) { - CHIP_ERROR err = aEncoder.EncodeList([&endpoint](const auto & encoder) -> CHIP_ERROR { - Descriptor::Structs::DeviceTypeStruct::Type deviceStruct; + DataModel::ListBuilder deviceTypesList; + ReturnErrorOnFailure(InteractionModelEngine::GetInstance()->GetDataModelProvider()->DeviceTypes(endpoint, deviceTypesList)); - auto deviceTypes = InteractionModelEngine::GetInstance()->GetDataModelProvider()->DeviceTypes(endpoint); - for (auto & type : deviceTypes.GetSpanValidForLifetime()) + auto deviceTypes = deviceTypesList.TakeBuffer(); + + CHIP_ERROR err = aEncoder.EncodeList([&deviceTypes](const auto & encoder) -> CHIP_ERROR { + Descriptor::Structs::DeviceTypeStruct::Type deviceStruct; + for (const auto & type : deviceTypes) { deviceStruct.deviceType = type.deviceTypeId; deviceStruct.revision = type.deviceTypeRevision; @@ -201,30 +211,30 @@ CHIP_ERROR DescriptorAttrAccess::ReadDeviceAttribute(EndpointId endpoint, Attrib return err; } -CHIP_ERROR DescriptorAttrAccess::ReadClientServerAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder, bool server) +CHIP_ERROR DescriptorAttrAccess::ReadServerClusters(EndpointId endpoint, AttributeValueEncoder & aEncoder) { - CHIP_ERROR err = aEncoder.EncodeList([&endpoint, server](const auto & encoder) -> CHIP_ERROR { - if (server) + DataModel::ListBuilder builder; + ReturnErrorOnFailure(InteractionModelEngine::GetInstance()->GetDataModelProvider()->ServerClusters(endpoint, builder)); + return aEncoder.EncodeList([&builder](const auto & encoder) -> CHIP_ERROR { + for (const auto & cluster : builder.TakeBuffer()) { - auto clusters = InteractionModelEngine::GetInstance()->GetDataModelProvider()->ServerClusters(endpoint); - for (auto & cluster : clusters.GetSpanValidForLifetime()) - { - ReturnErrorOnFailure(encoder.Encode(cluster.clusterId)); - } + ReturnErrorOnFailure(encoder.Encode(cluster.clusterId)); } - else + return CHIP_NO_ERROR; + }); +} + +CHIP_ERROR DescriptorAttrAccess::ReadClientClusters(EndpointId endpoint, AttributeValueEncoder & aEncoder) +{ + DataModel::ListBuilder clusterIdList; + ReturnErrorOnFailure(InteractionModelEngine::GetInstance()->GetDataModelProvider()->ClientClusters(endpoint, clusterIdList)); + return aEncoder.EncodeList([&clusterIdList](const auto & encoder) -> CHIP_ERROR { + for (const auto & id : clusterIdList.TakeBuffer()) { - auto clusters = InteractionModelEngine::GetInstance()->GetDataModelProvider()->ClientClusters(endpoint); - for (auto & id : clusters.GetSpanValidForLifetime()) - { - ReturnErrorOnFailure(encoder.Encode(id)); - } + ReturnErrorOnFailure(encoder.Encode(id)); } - return CHIP_NO_ERROR; }); - - return err; } CHIP_ERROR DescriptorAttrAccess::ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder) @@ -244,10 +254,10 @@ CHIP_ERROR DescriptorAttrAccess::Read(const ConcreteReadAttributePath & aPath, A return ReadDeviceAttribute(aPath.mEndpointId, aEncoder); } case ServerList::Id: { - return ReadClientServerAttribute(aPath.mEndpointId, aEncoder, true); + return ReadServerClusters(aPath.mEndpointId, aEncoder); } case ClientList::Id: { - return ReadClientServerAttribute(aPath.mEndpointId, aEncoder, false); + return ReadClientClusters(aPath.mEndpointId, aEncoder); } case PartsList::Id: { return ReadPartsAttribute(aPath.mEndpointId, aEncoder); diff --git a/src/app/clusters/microwave-oven-control-server/microwave-oven-control-server.cpp b/src/app/clusters/microwave-oven-control-server/microwave-oven-control-server.cpp index bdb614789f4b9b..5d823d0cafe3cb 100644 --- a/src/app/clusters/microwave-oven-control-server/microwave-oven-control-server.cpp +++ b/src/app/clusters/microwave-oven-control-server/microwave-oven-control-server.cpp @@ -16,6 +16,7 @@ * */ +#include "app/data-model-provider/MetadataList.h" #include #include #include @@ -249,15 +250,17 @@ void Instance::HandleSetCookingParameters(HandlerContext & ctx, const Commands:: if (startAfterSetting.HasValue()) { - DataModel::MetadataList acceptedCommands = - InteractionModelEngine::GetInstance()->GetDataModelProvider()->AcceptedCommands( - ConcreteClusterPath(mEndpointId, OperationalState::Id)); - Span acceptedCommandsSpan = acceptedCommands.GetSpanValidForLifetime(); - - bool commandExists = std::find_if(acceptedCommandsSpan.begin(), acceptedCommandsSpan.end(), - [](const DataModel::AcceptedCommandEntry & entry) { - return entry.commandId == OperationalState::Commands::Start::Id; - }) != acceptedCommandsSpan.end(); + + DataModel::ListBuilder acceptedCommandsList; + + InteractionModelEngine::GetInstance()->GetDataModelProvider()->AcceptedCommands( + ConcreteClusterPath(mEndpointId, OperationalState::Id), acceptedCommandsList); + auto acceptedCommands = acceptedCommandsList.TakeBuffer(); + + bool commandExists = + std::find_if(acceptedCommands.begin(), acceptedCommands.end(), [](const DataModel::AcceptedCommandEntry & entry) { + return entry.commandId == OperationalState::Commands::Start::Id; + }) != acceptedCommands.end(); VerifyOrExit( commandExists, status = Status::InvalidCommand; ChipLogError( diff --git a/src/app/data-model-provider/BUILD.gn b/src/app/data-model-provider/BUILD.gn index a80315a1f89c85..5804b0acf59cf5 100644 --- a/src/app/data-model-provider/BUILD.gn +++ b/src/app/data-model-provider/BUILD.gn @@ -25,6 +25,7 @@ source_set("data-model-provider") { "MetadataList.h", "MetadataLookup.cpp", "MetadataLookup.h", + "MetadataTypes.cpp", "MetadataTypes.h", "OperationTypes.h", "Provider.h", diff --git a/src/app/data-model-provider/MetadataList.cpp b/src/app/data-model-provider/MetadataList.cpp index c1d5479f57a5a7..564ccdf53f91cd 100644 --- a/src/app/data-model-provider/MetadataList.cpp +++ b/src/app/data-model-provider/MetadataList.cpp @@ -25,106 +25,157 @@ namespace app { namespace DataModel { namespace detail { -GenericMetadataList::~GenericMetadataList() +GenericAppendOnlyBuffer::~GenericAppendOnlyBuffer() { - Invalidate(); -} - -GenericMetadataList & GenericMetadataList::operator=(GenericMetadataList && other) -{ - if (this != &other) + if (mBufferIsAllocated && (mBuffer != nullptr)) { - // Generic metadata lists should not be used directly except for same-sized data - VerifyOrDie(this->mElementSize == other.mElementSize); - - if (mAllocated && (mBuffer != nullptr)) - { - chip::Platform::MemoryFree(mBuffer); - } - - this->mAllocated = other.mAllocated; - this->mBuffer = other.mBuffer; - this->mElementCount = other.mElementCount; - this->mCapacity = other.mCapacity; - this->mIsImmutable = other.mIsImmutable; - - other.mAllocated = false; - other.mBuffer = nullptr; - other.mElementCount = 0; - other.mCapacity = 0; - other.mIsImmutable = true; + Platform::MemoryFree(mBuffer); } - return *this; } -const void * GenericMetadataList::operator[](size_t index) const +GenericAppendOnlyBuffer::GenericAppendOnlyBuffer(GenericAppendOnlyBuffer && other) : mElementSize(other.mElementSize) { - VerifyOrDie(index < mElementCount); - return mBuffer + index * mElementSize; + // take over the data + mBuffer = other.mBuffer; + mElementCount = other.mElementCount; + mCapacity = other.mCapacity; + mBufferIsAllocated = other.mBufferIsAllocated; + + // clear other + other.mBuffer = nullptr; + other.mElementCount = 0; + other.mCapacity = 0; + other.mBufferIsAllocated = false; } -CHIP_ERROR GenericMetadataList::Reserve(size_t numElements) +GenericAppendOnlyBuffer & GenericAppendOnlyBuffer::operator=(GenericAppendOnlyBuffer && other) { - VerifyOrReturnError(!mIsImmutable, CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(mElementCount == 0, CHIP_ERROR_INCORRECT_STATE); + VerifyOrDie(mElementSize == other.mElementSize); + + if (mBufferIsAllocated && (mBuffer != nullptr)) + { + Platform::Impl::PlatformMemoryManagement::MemoryFree(mBuffer); + } + + // take over the data + mBuffer = other.mBuffer; + mElementCount = other.mElementCount; + mCapacity = other.mCapacity; + mBufferIsAllocated = other.mBufferIsAllocated; + + // clear other + other.mBuffer = nullptr; + other.mElementCount = 0; + other.mCapacity = 0; + other.mBufferIsAllocated = false; - if ((mBuffer != nullptr) && mAllocated) + return *this; +} + +CHIP_ERROR GenericAppendOnlyBuffer::EnsureAppendCapacity(size_t numElements) +{ + if (mCapacity >= mElementCount + numElements) { - chip::Platform::MemoryFree(mBuffer); + // Sufficient capacity already exists + return CHIP_NO_ERROR; } - mBuffer = static_cast(chip::Platform::MemoryCalloc(numElements, mElementSize)); + if (mBuffer == nullptr) + { + mBuffer = static_cast(Platform::MemoryCalloc(numElements, mElementSize)); + mCapacity = numElements; + mBufferIsAllocated = true; + return mBuffer != nullptr ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY; + } - VerifyOrReturnError(mBuffer != nullptr, CHIP_ERROR_NO_MEMORY); + // we already have the data in buffer. we have two choices: + // - allocated buffer needs to be extended + // - re-used const buffer needs to be copied over + if (mBufferIsAllocated) + { + auto new_buffer = static_cast(Platform::MemoryRealloc(mBuffer, (mElementCount + numElements) * mElementSize)); + VerifyOrReturnError(new_buffer != nullptr, CHIP_ERROR_NO_MEMORY); + mBuffer = new_buffer; + } + else + { + // this is NOT an allocated buffer, but it should become one + auto new_buffer = static_cast(Platform::MemoryCalloc(mElementCount + numElements, mElementSize)); + mBufferIsAllocated = true; + VerifyOrReturnError(new_buffer != nullptr, CHIP_ERROR_NO_MEMORY); + memcpy(new_buffer, mBuffer, mElementCount * mElementSize); + mBuffer = new_buffer; + } + mCapacity = mElementCount + numElements; - mAllocated = true; - mCapacity = numElements; return CHIP_NO_ERROR; } -CHIP_ERROR GenericMetadataList::AppendRaw(const void * buffer) +CHIP_ERROR GenericAppendOnlyBuffer::AppendSingleElementRaw(const void * buffer) { - VerifyOrReturnError(!mIsImmutable, CHIP_ERROR_INCORRECT_STATE); - VerifyOrReturnError(mElementCount < mCapacity, CHIP_ERROR_NO_MEMORY); + VerifyOrReturnError(mElementCount < mCapacity, CHIP_ERROR_BUFFER_TOO_SMALL); memcpy(mBuffer + mElementCount * mElementSize, buffer, mElementSize); mElementCount++; return CHIP_NO_ERROR; } -void GenericMetadataList::Invalidate() +CHIP_ERROR GenericAppendOnlyBuffer::AppendElementArrayRaw(const void * buffer, size_t numElements) { - if ((mBuffer != nullptr) && mAllocated) + ReturnErrorOnFailure(EnsureAppendCapacity(numElements)); + + memcpy(mBuffer + mElementCount * mElementSize, buffer, numElements * mElementSize); + mElementCount += numElements; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR GenericAppendOnlyBuffer::ReferenceExistingElementArrayRaw(const void * buffer, size_t numElements) +{ + if (mBuffer == nullptr) { - chip::Platform::MemoryFree(mBuffer); - mBuffer = nullptr; - mAllocated = false; + // we can NEVER append with 0 capacity, so const cast is safe + mBuffer = const_cast(static_cast(buffer)); + mElementCount = numElements; + // The assertions below are because we know the buffer is null/not allocated yet + VerifyOrDie(mCapacity == 0); + VerifyOrDie(!mBufferIsAllocated); + return CHIP_NO_ERROR; } - mCapacity = 0; - mElementCount = 0; - mCapacity = 0; - mIsImmutable = true; + + return AppendElementArrayRaw(buffer, numElements); } -CHIP_ERROR GenericMetadataList::CopyExistingBuffer(const void * buffer, size_t elements) +void GenericAppendOnlyBuffer::ReleaseBuffer(void *& buffer, size_t & size, bool & allocated) { - ReturnErrorOnFailure(Reserve(elements)); - memcpy(mBuffer, buffer, mElementSize * elements); - mIsImmutable = true; - mElementCount = elements; - mCapacity = elements; - return CHIP_NO_ERROR; + buffer = mBuffer; + size = mElementCount; + allocated = mBufferIsAllocated; + + // we release the ownership + mBuffer = nullptr; + mCapacity = 0; + mElementCount = 0; + mBufferIsAllocated = false; } -void GenericMetadataList::AcquireExistingBuffer(const void * buffer, size_t elements) +ScopedBuffer::~ScopedBuffer() { - Invalidate(); - mAllocated = false; - mElementCount = elements; - mCapacity = elements; - mIsImmutable = true; - // NOTE: const cast, however we are marked as immutable and not allocated, - // so will never perform any writes on mBuffer's contents or try to deallocate it. - mBuffer = static_cast(const_cast(buffer)); + if (mBuffer != nullptr) + { + Platform::MemoryFree(mBuffer); + } +} + +ScopedBuffer & ScopedBuffer::operator=(ScopedBuffer && other) +{ + if (mBuffer != nullptr) + { + Platform::MemoryFree(mBuffer); + } + + mBuffer = other.mBuffer; + other.mBuffer = nullptr; + return *this; } } // namespace detail diff --git a/src/app/data-model-provider/MetadataList.h b/src/app/data-model-provider/MetadataList.h index 37432363712939..5086a430749b93 100644 --- a/src/app/data-model-provider/MetadataList.h +++ b/src/app/data-model-provider/MetadataList.h @@ -18,10 +18,12 @@ #pragma once #include +#include #include #include #include +#include #include namespace chip { @@ -30,61 +32,106 @@ namespace DataModel { namespace detail { -// essentially a `void *` untyped metadata list base, -// so that actual functionality does not template-explode -class GenericMetadataList +class GenericAppendOnlyBuffer { public: - GenericMetadataList(size_t elementSize) : mElementSize(elementSize) {} - ~GenericMetadataList(); + GenericAppendOnlyBuffer(size_t elementSize) : mElementSize(elementSize) {} + ~GenericAppendOnlyBuffer(); - GenericMetadataList(const GenericMetadataList &) = delete; - GenericMetadataList & operator=(const GenericMetadataList & other) = delete; + GenericAppendOnlyBuffer(GenericAppendOnlyBuffer && other); + GenericAppendOnlyBuffer & operator=(GenericAppendOnlyBuffer &&); - GenericMetadataList(GenericMetadataList && other) { *this = std::move(other); } + GenericAppendOnlyBuffer() = delete; + GenericAppendOnlyBuffer & operator=(const GenericAppendOnlyBuffer &) = delete; - GenericMetadataList & operator=(GenericMetadataList && other); - const void * operator[](size_t index) const; + /// Ensure that at least the specified number of elements + /// can be appended to the internal buffer; + /// + /// This will cause the internal buffer to become and allocated buffer + CHIP_ERROR EnsureAppendCapacity(size_t numElements); - CHIP_ERROR Reserve(size_t numElements); - void Invalidate(); + bool IsEmpty() const { return mElementCount == 0; } - size_t ElementCount() const { return mElementCount; } - size_t Capacity() const { return mCapacity; } - bool Empty() const { return mElementCount == 0; } + /// Number of elements stored in the object. + size_t Size() const { return mElementCount; } protected: - /// Copy over the data from the given buffer - CHIP_ERROR CopyExistingBuffer(const void * buffer, size_t elements); + /// Appends a single element of mElementSize size. + /// + /// ALWAYS COPIES the given element internally. + /// Sufficient capacity MUST exist to append. + CHIP_ERROR AppendSingleElementRaw(const void * buffer); + + /// Appends a list of elements from a raw array. + /// + /// This ALWAYS COPIES the elements internally. + /// Additional capacity is AUTOMATICALLY ADDED. + CHIP_ERROR AppendElementArrayRaw(const void * buffer, size_t numElements); + + /// Appends a list of elements from a raw array. + /// + /// If the buffer contains no elements, this will just REFERENCE the given + /// buffer, so its lifetime MUST be longer than the lifetime of this buffer and + /// its usage. + /// + /// If the buffer already contains some elements, this will AUTOMATICALLY + /// add additional capacity and COPY the elements at the end of the internal array. + CHIP_ERROR ReferenceExistingElementArrayRaw(const void * buffer, size_t numElements); + + /// release ownership of any used buffer. + /// + /// Returns the current buffer details and releases ownership of it (clears internal state) + void ReleaseBuffer(void *& buffer, size_t & size, bool & allocated); - /// use existing buffer AS IS, without taking ownership. - void AcquireExistingBuffer(const void * buffer, size_t elements); - - CHIP_ERROR AppendRaw(const void * buffer); - const void * RawBuffer() const { return mBuffer; } +private: + const size_t mElementSize; // size of one element in the buffer + uint8_t * mBuffer = nullptr; + size_t mElementCount = 0; // how many elements are stored in the class + size_t mCapacity = 0; // how many elements can be stored in total in mBuffer + bool mBufferIsAllocated = false; // if mBuffer is an allocated buffer +}; - /// Marks a list as immutable and immutability is acquired - /// during const access (so this is const) - void SetImmutable() const { mIsImmutable = true; } +/// Represents a RAII instance owning a buffer. +/// +/// It auto-frees the owned buffer on destruction +class ScopedBuffer +{ +public: + ScopedBuffer(void * buffer) : mBuffer(buffer) {} + ~ScopedBuffer(); -private: - bool mAllocated = false; + ScopedBuffer(const ScopedBuffer &) = delete; + ScopedBuffer & operator=(const ScopedBuffer &) = delete; - // buffer may point to either allocated or re-used (e.g. from const arrays) buffers. - // buffer is assumed allocated if mAllocated is true. - uint8_t * mBuffer = nullptr; - size_t mElementSize; - size_t mElementCount = 0; - size_t mCapacity = 0; + ScopedBuffer(ScopedBuffer && other) : mBuffer(other.mBuffer) { other.mBuffer = nullptr; } + ScopedBuffer & operator=(ScopedBuffer && other); - // Set to true as soon as a span is obtained, since more writes may invalidate the span. - mutable bool mIsImmutable = false; +private: + void * mBuffer; }; } // namespace detail template -class MetadataList : public detail::GenericMetadataList +class ReadOnlyBuffer : public Span, detail::ScopedBuffer +{ +public: + ReadOnlyBuffer() : ScopedBuffer(nullptr) {} + ReadOnlyBuffer(const T * buffer, size_t size, bool allocated) : + Span(buffer, size), ScopedBuffer(allocated ? const_cast(static_cast(buffer)) : nullptr) + {} + ~ReadOnlyBuffer() = default; + + ReadOnlyBuffer & operator=(ReadOnlyBuffer && other) + { + *static_cast *>(this) = other; + *static_cast(this) = std::move(other); + return *this; + } +}; + +template +class ListBuilder : public detail::GenericAppendOnlyBuffer { public: using SpanType = Span; @@ -97,57 +144,44 @@ class MetadataList : public detail::GenericMetadataList // implementation does not actually report that. static_assert(std::is_trivially_destructible_v); - MetadataList() : GenericMetadataList(sizeof(T)) {} - MetadataList(const MetadataList &) = delete; - MetadataList & operator=(const MetadataList & other) = delete; + ListBuilder() : GenericAppendOnlyBuffer(sizeof(T)) {} - MetadataList(MetadataList && other) : GenericMetadataList(sizeof(T)) { *this = std::move(other); } + ListBuilder(const ListBuilder &) = delete; + ListBuilder & operator=(const ListBuilder & other) = delete; - MetadataList & operator=(MetadataList && other) + ListBuilder(ListBuilder && other) : GenericAppendOnlyBuffer(sizeof(T)) { *this = std::move(other); } + + ListBuilder & operator=(ListBuilder && other) { - *static_cast(this) = std::move(other); + *static_cast(this) = std::move(other); return *this; } - const T & operator[](size_t index) { return *static_cast(GenericMetadataList::operator[](index)); } + /// Reference methods attempt to reference the existing array IN PLACE + /// so its lifetime is assumed to be longer than the usage of this list. + CHIP_ERROR ReferenceExisting(SpanType span) { return ReferenceExistingElementArrayRaw(span.data(), span.size()); } - template - static MetadataList FromArray(const std::array & arr) - { - MetadataList list; + /// Append always attempts to append/extend existing memory. + /// + /// Automatically attempts to allocate sufficient space to fulfill the element + /// requirements. + CHIP_ERROR AppendElements(SpanType span) { return AppendElementArrayRaw(span.data(), span.size()); } - if (list.CopyExistingBuffer(arr.data(), arr.size()) != CHIP_NO_ERROR) - { - list.Invalidate(); - } + /// Append a single element. + /// Sufficent append capacity MUST exist. + CHIP_ERROR Append(const T & value) { return AppendSingleElementRaw(&value); } - return list; - } - - template - static MetadataList FromConstArray(const std::array & arr) + /// Once a list is built, the data is taken as a scoped SPAN that owns its data + /// and the original list is cleared + ReadOnlyBuffer TakeBuffer() { - MetadataList list; - list.AcquireExistingBuffer(arr.data(), arr.size()); - return list; - } + void * buffer; + size_t size; + bool allocated; + ReleaseBuffer(buffer, size, allocated); - static MetadataList FromConstSpan(const Span & span) - { - MetadataList list; - list.AcquireExistingBuffer(span.data(), span.size()); - return list; - } - - size_t Size() const { return ElementCount(); } - - Span GetSpanValidForLifetime() const - { - SetImmutable(); - return Span(static_cast(RawBuffer()), ElementCount()); + return ReadOnlyBuffer(static_cast(buffer), size, allocated); } - - CHIP_ERROR Append(const T & value) { return AppendRaw(&value); } }; } // namespace DataModel diff --git a/src/app/data-model-provider/MetadataLookup.cpp b/src/app/data-model-provider/MetadataLookup.cpp index be94807b6c287f..5ec6b451ed264d 100644 --- a/src/app/data-model-provider/MetadataLookup.cpp +++ b/src/app/data-model-provider/MetadataLookup.cpp @@ -15,6 +15,8 @@ */ #include +#include + namespace chip { namespace app { namespace DataModel { @@ -26,12 +28,10 @@ std::optional ServerClusterFinder::Find(const ConcreteCluste if (mEndpointId != path.mEndpointId) { mEndpointId = path.mEndpointId; - mClusterEntries = mProvider->ServerClusters(path.mEndpointId); + mClusterEntries = mProvider->ServerClustersIgnoreError(path.mEndpointId); } - auto serverClustersSpan = mClusterEntries.GetSpanValidForLifetime(); - - for (auto & clusterEntry : serverClustersSpan) + for (auto & clusterEntry : mClusterEntries) { if (clusterEntry.clusterId == path.mClusterId) { @@ -49,11 +49,10 @@ std::optional AttributeFinder::Find(const ConcreteAttributePath if (mClusterPath != path) { mClusterPath = path; - mAttributes = mProvider->Attributes(path); + mAttributes = mProvider->AttributesIgnoreError(path); } - auto attributesSpan = mAttributes.GetSpanValidForLifetime(); - for (auto & attributeEntry : attributesSpan) + for (auto & attributeEntry : mAttributes) { if (attributeEntry.attributeId == path.mAttributeId) { @@ -64,10 +63,15 @@ std::optional AttributeFinder::Find(const ConcreteAttributePath return std::nullopt; } +EndpointFinder::EndpointFinder(ProviderMetadataTree * provider) : mProvider(provider) +{ + VerifyOrReturn(mProvider != nullptr); + mEndpoints = mProvider->EndpointsIgnoreError(); +} + std::optional EndpointFinder::Find(EndpointId endpointId) { - auto endpointsSpan = mEndpoints.GetSpanValidForLifetime(); - for (auto & endpointEntry : endpointsSpan) + for (auto & endpointEntry : mEndpoints) { if (endpointEntry.id == endpointId) { diff --git a/src/app/data-model-provider/MetadataLookup.h b/src/app/data-model-provider/MetadataLookup.h index 573b46d30c2ddc..9c2978d71a5ae6 100644 --- a/src/app/data-model-provider/MetadataLookup.h +++ b/src/app/data-model-provider/MetadataLookup.h @@ -44,7 +44,7 @@ class ServerClusterFinder private: ProviderMetadataTree * mProvider; EndpointId mEndpointId = kInvalidEndpointId; - MetadataList mClusterEntries; + ReadOnlyBuffer mClusterEntries; }; /// Helps search for a specific server attribute in the given @@ -61,7 +61,7 @@ class AttributeFinder private: ProviderMetadataTree * mProvider; ConcreteClusterPath mClusterPath; - MetadataList mAttributes; + ReadOnlyBuffer mAttributes; }; /// Helps search for a specific server endpoint in the given @@ -71,19 +71,12 @@ class AttributeFinder class EndpointFinder { public: - EndpointFinder(ProviderMetadataTree * provider) : mProvider(provider) - { - if (mProvider != nullptr) - { - mEndpoints = mProvider->Endpoints(); - } - } - + EndpointFinder(ProviderMetadataTree * provider); std::optional Find(EndpointId endpointId); private: ProviderMetadataTree * mProvider; - MetadataList mEndpoints; + ReadOnlyBuffer mEndpoints; }; } // namespace DataModel diff --git a/src/app/data-model-provider/MetadataTypes.cpp b/src/app/data-model-provider/MetadataTypes.cpp new file mode 100644 index 00000000000000..6d87d9b5ea54ac --- /dev/null +++ b/src/app/data-model-provider/MetadataTypes.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 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 + +namespace chip { +namespace app { +namespace DataModel { + +ReadOnlyBuffer ProviderMetadataTree::EndpointsIgnoreError() +{ + + ListBuilder builder; + (void) Endpoints(builder); + return builder.TakeBuffer(); +} + +ReadOnlyBuffer ProviderMetadataTree::ServerClustersIgnoreError(EndpointId endpointId) +{ + + ListBuilder builder; + (void) ServerClusters(endpointId, builder); + return builder.TakeBuffer(); +} + +ReadOnlyBuffer ProviderMetadataTree::AttributesIgnoreError(const ConcreteClusterPath & path) +{ + ListBuilder builder; + (void) Attributes(path, builder); + return builder.TakeBuffer(); +} + +} // namespace DataModel +} // namespace app +} // namespace chip diff --git a/src/app/data-model-provider/MetadataTypes.h b/src/app/data-model-provider/MetadataTypes.h index 8a8332c40f2d78..5b6bccb863e660 100644 --- a/src/app/data-model-provider/MetadataTypes.h +++ b/src/app/data-model-provider/MetadataTypes.h @@ -158,16 +158,16 @@ class ProviderMetadataTree using SemanticTag = Clusters::Descriptor::Structs::SemanticTagStruct::Type; - virtual MetadataList Endpoints() = 0; + virtual CHIP_ERROR Endpoints(ListBuilder & builder) = 0; - virtual MetadataList SemanticTags(EndpointId endpointId) = 0; - virtual MetadataList DeviceTypes(EndpointId endpointId) = 0; - virtual MetadataList ClientClusters(EndpointId endpointId) = 0; - virtual MetadataList ServerClusters(EndpointId endpointId) = 0; + virtual CHIP_ERROR SemanticTags(EndpointId endpointId, ListBuilder & builder) = 0; + virtual CHIP_ERROR DeviceTypes(EndpointId endpointId, ListBuilder & builder) = 0; + virtual CHIP_ERROR ClientClusters(EndpointId endpointId, ListBuilder & builder) = 0; + virtual CHIP_ERROR ServerClusters(EndpointId endpointId, ListBuilder & builder) = 0; - virtual MetadataList Attributes(const ConcreteClusterPath & path) = 0; - virtual MetadataList GeneratedCommands(const ConcreteClusterPath & path) = 0; - virtual MetadataList AcceptedCommands(const ConcreteClusterPath & path) = 0; + virtual CHIP_ERROR Attributes(const ConcreteClusterPath & path, ListBuilder & builder) = 0; + virtual CHIP_ERROR GeneratedCommands(const ConcreteClusterPath & path, ListBuilder & builder) = 0; + virtual CHIP_ERROR AcceptedCommands(const ConcreteClusterPath & path, ListBuilder & builder) = 0; /// Workaround function to report attribute change. /// @@ -186,6 +186,12 @@ class ProviderMetadataTree /// TODO: We should remove this function when the AttributeAccessInterface/CommandHandlerInterface is able to report /// the attribute changes. virtual void Temporary_ReportAttributeChanged(const AttributePathParams & path) = 0; + + // "convenience" functions that just return the data and ignore the error + // This returns the builder as-is even after the error (e.g. not found would return empty data) + ReadOnlyBuffer EndpointsIgnoreError(); + ReadOnlyBuffer ServerClustersIgnoreError(EndpointId endpointId); + ReadOnlyBuffer AttributesIgnoreError(const ConcreteClusterPath & path); }; } // namespace DataModel diff --git a/src/app/data-model-provider/tests/TestMetadataList.cpp b/src/app/data-model-provider/tests/TestMetadataList.cpp index 663dfae906303d..f9fd7ab62be208 100644 --- a/src/app/data-model-provider/tests/TestMetadataList.cpp +++ b/src/app/data-model-provider/tests/TestMetadataList.cpp @@ -16,8 +16,8 @@ * limitations under the License. */ +#include #include -#include #include #include @@ -54,21 +54,17 @@ struct IdAndValue } }; -TEST_F(TestMetadataList, MetadataListWorks) +TEST_F(TestMetadataList, ListBuilderWorks) { - MetadataList> list1; + ListBuilder> list1; EXPECT_EQ(list1.Size(), 0u); - EXPECT_TRUE(list1.Empty()); + EXPECT_TRUE(list1.IsEmpty()); - // Reservation should always work when empty - ASSERT_EQ(list1.Reserve(5), CHIP_NO_ERROR); - EXPECT_EQ(list1.Capacity(), 5u); + ASSERT_EQ(list1.EnsureAppendCapacity(3), CHIP_NO_ERROR); EXPECT_EQ(list1.Size(), 0u); - EXPECT_TRUE(list1.Empty()); + EXPECT_TRUE(list1.IsEmpty()); - // You can re-reserve differently if still empty. - ASSERT_EQ(list1.Reserve(2), CHIP_NO_ERROR); - EXPECT_EQ(list1.Capacity(), 2u); + ASSERT_EQ(list1.EnsureAppendCapacity(2), CHIP_NO_ERROR); // Values can be appended until the capacity. EXPECT_EQ(list1.Append({ 0xA1, 111 }), CHIP_NO_ERROR); @@ -77,22 +73,31 @@ TEST_F(TestMetadataList, MetadataListWorks) EXPECT_EQ(list1.Append({ 0xA2, 222 }), CHIP_NO_ERROR); EXPECT_EQ(list1.Size(), 2u); - EXPECT_EQ(list1.Append({ 0xA3, 333 }), CHIP_ERROR_NO_MEMORY); - EXPECT_EQ(list1.Size(), 2u); + // capacity is 3 because of the largest ensure + EXPECT_EQ(list1.Append({ 0xA3, 333 }), CHIP_NO_ERROR); + EXPECT_EQ(list1.Size(), 3u); + + EXPECT_EQ(list1.Append({ 0xA4, 444 }), CHIP_ERROR_BUFFER_TOO_SMALL); + EXPECT_EQ(list1.Size(), 3u); - MetadataList> list2 = std::move(list1); + ListBuilder> list2 = std::move(list1); // Moved-from list is "empty", un-Metadata and span is empty. - EXPECT_EQ(list1.Size(), 0u); // NOLINT(bugprone-use-after-move) - EXPECT_EQ(list1.Capacity(), 0u); // NOLINT(bugprone-use-after-move) - EXPECT_TRUE(list1.GetSpanValidForLifetime().empty()); // NOLINT(bugprone-use-after-move) + EXPECT_EQ(list1.Size(), 0u); // NOLINT(bugprone-use-after-move) + EXPECT_TRUE(list1.IsEmpty()); // NOLINT(bugprone-use-after-move) + EXPECT_TRUE(list1.TakeBuffer().empty()); // NOLINT(bugprone-use-after-move) // Moved-to list has storage. - EXPECT_EQ(list2.Size(), 2u); + EXPECT_EQ(list2.Size(), 3u); + EXPECT_FALSE(list2.IsEmpty()); // A span can be obtained over the list. - decltype(list2)::SpanType contents = list2.GetSpanValidForLifetime(); - EXPECT_EQ(contents.size(), 2u); + auto contents = list2.TakeBuffer(); + EXPECT_EQ(contents.size(), 3u); + + // contents takes ownersip of the list and clears it (and has no capacity) + EXPECT_TRUE(list2.IsEmpty()); + EXPECT_EQ(list2.Append({ 1, 2 }), CHIP_ERROR_BUFFER_TOO_SMALL); size_t idx = 0; for (const auto & element : contents) @@ -102,294 +107,100 @@ TEST_F(TestMetadataList, MetadataListWorks) EXPECT_EQ(element.value, 111 * static_cast(oneBasedIndex)); ++idx; } - EXPECT_EQ(idx, 2u); - - // After getting a span, list becomes immutable and it is no longer possible to append to the list. - EXPECT_EQ(list2.Append({ 0xA3, 333 }), CHIP_ERROR_INCORRECT_STATE); - EXPECT_EQ(list2.Size(), 2u); - EXPECT_EQ(list2.Capacity(), 2u); - - // Cannot re-reserve once the list has become immutable due to span-taking. - EXPECT_EQ(list2.Reserve(6), CHIP_ERROR_INCORRECT_STATE); + EXPECT_EQ(idx, 3u); } -static constexpr std::array kConstantArray{ 1, 2, 3 }; - -TEST_F(TestMetadataList, MetadataListConvertersWork) +TEST_F(TestMetadataList, ListBuilderConvertersWorks) { { - MetadataList list{ MetadataList::FromArray(std::array{ 1, 2, 3 }) }; - EXPECT_FALSE(list.Empty()); - EXPECT_EQ(list.Size(), 3u); - EXPECT_EQ(list[0], 1); - EXPECT_EQ(list[1], 2); - EXPECT_EQ(list[2], 3); + ListBuilder list; + std::array kArray{ 1, 2, 3 }; + EXPECT_EQ(list.ReferenceExisting(Span(kArray)), CHIP_NO_ERROR); auto list2 = std::move(list); EXPECT_EQ(list.Size(), 0u); // NOLINT(bugprone-use-after-move) - auto list2Span = list2.GetSpanValidForLifetime(); + auto list2Span = list2.TakeBuffer(); + EXPECT_TRUE(list2.IsEmpty()); // took over EXPECT_EQ(list2Span.size(), 3u); EXPECT_EQ(list2Span[0], 1); EXPECT_EQ(list2Span[1], 2); EXPECT_EQ(list2Span[2], 3); - - EXPECT_EQ(list2.Reserve(10), CHIP_ERROR_INCORRECT_STATE); - EXPECT_EQ(list2.Append(4), CHIP_ERROR_INCORRECT_STATE); - } - - { - MetadataList list1{ MetadataList::FromConstArray(kConstantArray) }; - EXPECT_EQ(list1.Size(), 3u); - EXPECT_EQ(list1[0], 1); - EXPECT_EQ(list1[1], 2); - EXPECT_EQ(list1[2], 3); - - EXPECT_EQ(list1.Reserve(10), CHIP_ERROR_INCORRECT_STATE); - EXPECT_EQ(list1.Append(4), CHIP_ERROR_INCORRECT_STATE); - - MetadataList list2{ MetadataList::FromConstArray(kConstantArray) }; - EXPECT_EQ(list2.Size(), 3u); - EXPECT_EQ(list2[0], 1); - EXPECT_EQ(list2[1], 2); - EXPECT_EQ(list2[2], 3); - - auto list1Span = list1.GetSpanValidForLifetime(); - auto list2Span = list2.GetSpanValidForLifetime(); - - EXPECT_EQ(list1Span.data(), list2Span.data()); - EXPECT_EQ(list1Span.size(), list2Span.size()); - EXPECT_EQ(list1Span.data(), kConstantArray.data()); } { - MetadataList list1{ MetadataList::FromConstSpan(Span{ kConstantArray }) }; - EXPECT_EQ(list1.Size(), 3u); - EXPECT_EQ(list1[0], 1); - EXPECT_EQ(list1[1], 2); - EXPECT_EQ(list1[2], 3); - - EXPECT_EQ(list1.Reserve(10), CHIP_ERROR_INCORRECT_STATE); - EXPECT_EQ(list1.Append(4), CHIP_ERROR_INCORRECT_STATE); - - MetadataList list2{ MetadataList::FromConstSpan(Span{ kConstantArray }) }; - EXPECT_EQ(list2.Size(), 3u); - EXPECT_EQ(list2[0], 1); - EXPECT_EQ(list2[1], 2); - EXPECT_EQ(list2[2], 3); - - auto list1Span = list1.GetSpanValidForLifetime(); - auto list2Span = list2.GetSpanValidForLifetime(); - - EXPECT_EQ(list1Span.data(), list2Span.data()); - EXPECT_EQ(list1Span.size(), list2Span.size()); - EXPECT_EQ(list1Span.data(), kConstantArray.data()); - } -} - -enum MinCommandPrivilege : uint8_t -{ - kOperate = 0u, - kManage = 1u, - kAdmin = 2u, - - kMax = kAdmin -}; - -static constexpr uint16_t kPrivilegeFieldWidth = 0x3; -static constexpr uint16_t kPrivilegeFieldMask = static_cast((1u << kPrivilegeFieldWidth) - 1); -static_assert(MinCommandPrivilege::kMax <= kPrivilegeFieldMask, "Privilege mask is not wide enough"); - -// Bitmask values for different Command qualities. -enum class CommandMetadataFlags : uint16_t -{ - kFabricScoped = 0x1 << 0, - kTimed = 0x1 << 1, // `T` quality on commands - kLargeMessage = 0x1 << 2, // `L` quality on commands - kIsResponse = 0x1 << 3, // Command is server => client response - - kMinPrivilegeValueMask = kPrivilegeFieldMask << 4 - -}; - -typedef BitMask CommandMetadata; - -// MinCommandPrivilege GetMinCommandPrivilege(CommandMetadata metadata) const { -// return static_cast(metadata.GetField(CommandMetadataFlags::kMinPrivilegeValueMask)); -// } - -struct CommandEntry -{ - CommandId mei; - CommandMetadata metadata; -}; - -enum class NetworkCommissioningFeatureBits : uint8_t -{ - // TODO: NOT REAL VALUEs - kWifi = 1 << 0, - kThread = 1 << 1, - kEthernet = 1 << 2, -}; - -enum NetworkCommissioningCommands : CommandId -{ - kScanNetworks = 0x00u, // | client => server | ScanNetworksResponse | A | WI \| TH - kScanNetworksResponse = 0x01u, // | client <= server | N | | WI \| TH - kAddOrUpdateWiFiNetwork = 0x02u, // | client => server | NetworkConfigResponse | A | WI - kAddOrUpdateThreadNetwork = 0x03u, // | client => server | NetworkConfigResponse | A | TH - kRemoveNetwork = 0x04u, // | client => server | NetworkConfigResponse | A | WI \| TH - kNetworkConfigResponse = 0x05u, // | client <= server | N | | WI \| TH - kConnectNetwork = 0x06u, // | client => server | ConnectNetworkResponse | A | WI \| TH - kConnectNetworkResponse = 0x07u, // | client <= server | N | | WI \| TH - kReorderNetwork = 0x08u, // | client => server | NetworkConfigResponse | A | WI \| TH + ListBuilder list; + std::array kArray{ 1, 2, 3 }; + std::array kArray2{ 4, 5, 6 }; + EXPECT_EQ(list.ReferenceExisting(Span(kArray)), CHIP_NO_ERROR); + EXPECT_EQ(list.ReferenceExisting(Span(kArray2)), CHIP_NO_ERROR); -}; - -static const std::array kAllCommands{ - CommandEntry{ kScanNetworks, - CommandMetadata{}.SetField(CommandMetadataFlags::kMinPrivilegeValueMask, MinCommandPrivilege::kAdmin) }, - CommandEntry{ kScanNetworksResponse, CommandMetadata{}.Set(CommandMetadataFlags::kIsResponse) }, - CommandEntry{ kAddOrUpdateWiFiNetwork, - CommandMetadata{}.SetField(CommandMetadataFlags::kMinPrivilegeValueMask, MinCommandPrivilege::kAdmin) }, - CommandEntry{ kAddOrUpdateThreadNetwork, - CommandMetadata{}.SetField(CommandMetadataFlags::kMinPrivilegeValueMask, MinCommandPrivilege::kAdmin) }, - CommandEntry{ kRemoveNetwork, - CommandMetadata{}.SetField(CommandMetadataFlags::kMinPrivilegeValueMask, MinCommandPrivilege::kAdmin) }, - CommandEntry{ kNetworkConfigResponse, CommandMetadata{}.Set(CommandMetadataFlags::kIsResponse) }, - CommandEntry{ kConnectNetwork, - CommandMetadata{}.SetField(CommandMetadataFlags::kMinPrivilegeValueMask, MinCommandPrivilege::kAdmin) }, - CommandEntry{ kConnectNetworkResponse, CommandMetadata{}.Set(CommandMetadataFlags::kIsResponse) }, - CommandEntry{ kReorderNetwork, - CommandMetadata{}.SetField(CommandMetadataFlags::kMinPrivilegeValueMask, MinCommandPrivilege::kAdmin) }, -}; - -using FilterPredicate = bool (*)(void * context, void * object); -template -MetadataList FilterElements(Span elementTable, std::function supportedPredicate) -{ - MetadataList result; + auto list2 = std::move(list); + EXPECT_EQ(list.Size(), 0u); // NOLINT(bugprone-use-after-move) - if (result.Reserve(elementTable.size()) != CHIP_NO_ERROR) - { - result.Invalidate(); - return result; + auto list2Span = list2.TakeBuffer(); + EXPECT_TRUE(list2.IsEmpty()); // took over + EXPECT_EQ(list2Span.size(), 6u); + EXPECT_EQ(list2Span[0], 1); + EXPECT_EQ(list2Span[1], 2); + EXPECT_EQ(list2Span[2], 3); + EXPECT_EQ(list2Span[3], 4); + EXPECT_EQ(list2Span[4], 5); + EXPECT_EQ(list2Span[5], 6); } - for (const auto & element : elementTable) { - if (!supportedPredicate(element)) - { - continue; - } + ListBuilder list; - // Append as much as we can - (void) result.Append(element); - } + EXPECT_EQ(list.Append(10), CHIP_ERROR_BUFFER_TOO_SMALL); + EXPECT_EQ(list.EnsureAppendCapacity(5), CHIP_NO_ERROR); - return result; -} + EXPECT_EQ(list.Append(10), CHIP_NO_ERROR); + EXPECT_EQ(list.Append(11), CHIP_NO_ERROR); -class MiniCluster -{ -public: - MiniCluster() {} - virtual ~MiniCluster() {} + std::array kArray{ 1, 2, 3 }; - virtual MetadataList GetSupportedCommands() const - { - return FilterElements(Span{ kAllCommands.data(), kAllCommands.size() }, - [this](const CommandEntry & entry) { return this->IsCommandSupported(entry.mei); }); - } + EXPECT_EQ(list.ReferenceExisting(Span(kArray)), CHIP_NO_ERROR); -#if 0 - virtual bool IsCommandSupported(CommandId commandId) const - { - using Commands = NetworkCommissioningCommands; - - if (commandId > Commands::kReorderNetwork) - { - return false; - } - - if (mFeatures.HasAny(NetworkCommissioningFeatureBits::kWifi, NetworkCommissioningFeatureBits::kThread)) - { - if ((commandId >= Commands::kScanNetworks) && (commandId <= Commands::kScanNetworksResponse)) - { - return true; - } - - if ((commandId >= Commands::kRemoveNetwork) && (commandId <= Commands::kReorderNetwork)) - { - return true; - } - } - - if (mFeatures.Has(NetworkCommissioningFeatureBits::kWifi)) - { - if (commandId == Commands::kAddOrUpdateWiFiNetwork) - { - return true; - } - } - - if (mFeatures.Has(NetworkCommissioningFeatureBits::kThread)) - { - if (commandId == Commands::kAddOrUpdateThreadNetwork) - { - return true; - } - } - - return false; - } -#endif // 0 + auto list2 = std::move(list); + EXPECT_EQ(list.Size(), 0u); // NOLINT(bugprone-use-after-move) - virtual bool IsCommandSupported(CommandId commandId) const - { - using Commands = NetworkCommissioningCommands; - - switch (commandId) - { - case Commands::kScanNetworks: - case Commands::kScanNetworksResponse: - case Commands::kRemoveNetwork: - case Commands::kNetworkConfigResponse: - case Commands::kConnectNetwork: - case Commands::kConnectNetworkResponse: - case Commands::kReorderNetwork: - return mFeatures.HasAny(NetworkCommissioningFeatureBits::kWifi, NetworkCommissioningFeatureBits::kThread); - case Commands::kAddOrUpdateWiFiNetwork: - return mFeatures.Has(NetworkCommissioningFeatureBits::kWifi); - case Commands::kAddOrUpdateThreadNetwork: - return mFeatures.Has(NetworkCommissioningFeatureBits::kThread); - default: - return false; - } + auto list2Span = list2.TakeBuffer(); + EXPECT_TRUE(list2.IsEmpty()); // took over + EXPECT_EQ(list2Span.size(), 5u); + EXPECT_EQ(list2Span[0], 10); + EXPECT_EQ(list2Span[1], 11); + EXPECT_EQ(list2Span[2], 1); + EXPECT_EQ(list2Span[3], 2); + EXPECT_EQ(list2Span[4], 3); } + { + ListBuilder list; - void SetFeatures(BitFlags features) { mFeatures = features; } - -private: - BitFlags mFeatures{}; -}; + EXPECT_EQ(list.Append(10), CHIP_ERROR_BUFFER_TOO_SMALL); + EXPECT_EQ(list.EnsureAppendCapacity(1), CHIP_NO_ERROR); -TEST_F(TestMetadataList, CommandsForFeaturesAreAsExpected) -{ - MiniCluster cluster; + EXPECT_EQ(list.Append(10), CHIP_NO_ERROR); + EXPECT_EQ(list.Append(11), CHIP_ERROR_BUFFER_TOO_SMALL); - { - cluster.SetFeatures(BitFlags{}.Set(NetworkCommissioningFeatureBits::kWifi)); + std::array kArray{ 1, 2, 3 }; - auto supportedCommands = cluster.GetSupportedCommands(); - EXPECT_EQ(supportedCommands.Size(), 8u); - } + EXPECT_EQ(list.AppendElements(Span(kArray)), CHIP_NO_ERROR); + EXPECT_EQ(list.ReferenceExisting(Span(kArray)), CHIP_NO_ERROR); - { - cluster.SetFeatures(BitFlags{}.Set(NetworkCommissioningFeatureBits::kEthernet)); + auto list2 = std::move(list); + EXPECT_EQ(list.Size(), 0u); // NOLINT(bugprone-use-after-move) - auto supportedCommands = cluster.GetSupportedCommands(); - EXPECT_EQ(supportedCommands.Size(), 0u); + auto list2Span = list2.TakeBuffer(); + EXPECT_TRUE(list2.IsEmpty()); // took over + EXPECT_EQ(list2Span.size(), 7u); + EXPECT_EQ(list2Span[0], 10); + EXPECT_EQ(list2Span[1], 1); + EXPECT_EQ(list2Span[2], 2); + EXPECT_EQ(list2Span[3], 3); + EXPECT_EQ(list2Span[4], 1); + EXPECT_EQ(list2Span[5], 2); + EXPECT_EQ(list2Span[6], 3); } } diff --git a/src/data-model-providers/codegen/CodegenDataModelProvider.cpp b/src/data-model-providers/codegen/CodegenDataModelProvider.cpp index d91b1be0a749ab..a7572fbb0322f7 100644 --- a/src/data-model-providers/codegen/CodegenDataModelProvider.cpp +++ b/src/data-model-providers/codegen/CodegenDataModelProvider.cpp @@ -63,165 +63,6 @@ DataModel::AcceptedCommandEntry AcceptedCommandEntryFor(const ConcreteCommandPat return entry; } -/// Fills `result` with accepted command data. In case of failures, -/// returns the first failure (and stops filling the result, which may -/// be partial) -CHIP_ERROR FetchAcceptedCommands(const ConcreteClusterPath & path, const EmberAfCluster * serverCluster, - DataModel::MetadataList & result) -{ - - CommandHandlerInterface * interface = - CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(path.mEndpointId, path.mClusterId); - if (interface != nullptr) - { - size_t commandCount = 0; - - CHIP_ERROR err = interface->EnumerateAcceptedCommands( - path, - [](CommandId id, void * context) -> Loop { - *reinterpret_cast(context) += 1; - return Loop::Continue; - }, - reinterpret_cast(&commandCount)); - - if (err == CHIP_NO_ERROR) - { - using EnumerationData = struct - { - ConcreteCommandPath commandPath; - DataModel::MetadataList acceptedCommandList; - CHIP_ERROR processingError; - }; - - EnumerationData enumerationData; - enumerationData.commandPath = ConcreteCommandPath(path.mEndpointId, path.mClusterId, kInvalidCommandId); - enumerationData.processingError = CHIP_NO_ERROR; - - ReturnErrorOnFailure(enumerationData.acceptedCommandList.Reserve(commandCount)); - - ReturnErrorOnFailure(interface->EnumerateAcceptedCommands( - path, - [](CommandId commandId, void * context) -> Loop { - auto input = reinterpret_cast(context); - input->commandPath.mCommandId = commandId; - CHIP_ERROR appendError = input->acceptedCommandList.Append(AcceptedCommandEntryFor(input->commandPath)); - if (appendError != CHIP_NO_ERROR) - { - input->processingError = appendError; - return Loop::Break; - } - return Loop::Continue; - }, - reinterpret_cast(&enumerationData))); - ReturnErrorOnFailure(enumerationData.processingError); - - // the two invocations MUST return the same sizes. - VerifyOrReturnError(enumerationData.acceptedCommandList.Size() == commandCount, CHIP_ERROR_INTERNAL); - - result = std::move(enumerationData.acceptedCommandList); - return CHIP_NO_ERROR; - } - VerifyOrReturnError(err == CHIP_ERROR_NOT_IMPLEMENTED, err); - } - - if ((serverCluster == nullptr) || (serverCluster->acceptedCommandList == nullptr)) - { - // No data if cluster does not exist or cluster has no accepted commands - return CHIP_NO_ERROR; - } - const chip::CommandId * endOfList = serverCluster->acceptedCommandList; - while (*endOfList != kInvalidCommandId) - { - endOfList++; - } - const size_t commandCount = static_cast(endOfList - serverCluster->acceptedCommandList); - - ReturnErrorOnFailure(result.Reserve(commandCount)); - - ConcreteCommandPath commandPath = ConcreteCommandPath(path.mEndpointId, path.mClusterId, kInvalidCommandId); - for (const chip::CommandId * p = serverCluster->acceptedCommandList; p != endOfList; p++) - { - commandPath.mCommandId = *p; - ReturnErrorOnFailure(result.Append(AcceptedCommandEntryFor(commandPath))); - } - - return CHIP_NO_ERROR; -} - -/// Fills `result` with generated command data. In case of failures, -/// returns the first failure (and stops filling the result, which may -/// be partial) -CHIP_ERROR FetchGeneratedCommands(const ConcreteClusterPath & path, const EmberAfCluster * serverCluster, - DataModel::MetadataList & result) -{ - CommandHandlerInterface * interface = - CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(path.mEndpointId, path.mClusterId); - if (interface != nullptr) - { - size_t commandCount = 0; - - CHIP_ERROR err = interface->EnumerateGeneratedCommands( - path, - [](CommandId id, void * context) -> Loop { - *reinterpret_cast(context) += 1; - return Loop::Continue; - }, - reinterpret_cast(&commandCount)); - - if (err == CHIP_NO_ERROR) - { - - using EnumerationData = struct - { - DataModel::MetadataList generatedCommandList; - CHIP_ERROR processingError; - }; - EnumerationData enumerationData; - enumerationData.processingError = CHIP_NO_ERROR; - - ReturnErrorOnFailure(enumerationData.generatedCommandList.Reserve(commandCount)); - - ReturnErrorOnFailure(interface->EnumerateGeneratedCommands( - path, - [](CommandId id, void * context) -> Loop { - auto input = reinterpret_cast(context); - - CHIP_ERROR appendError = input->generatedCommandList.Append(id); - if (appendError != CHIP_NO_ERROR) - { - input->processingError = appendError; - return Loop::Break; - } - return Loop::Continue; - }, - reinterpret_cast(&enumerationData))); - ReturnErrorOnFailure(enumerationData.processingError); - - // the two invocations MUST return the same sizes. - VerifyOrReturnError(enumerationData.generatedCommandList.Size() == commandCount, CHIP_ERROR_INTERNAL); - - result = std::move(enumerationData.generatedCommandList); - return CHIP_NO_ERROR; - } - VerifyOrReturnError(err == CHIP_ERROR_NOT_IMPLEMENTED, err); - } - - if ((serverCluster == nullptr) || (serverCluster->generatedCommandList == nullptr)) - { - // No data if cluster does not exist or cluster has no generated commands - return CHIP_NO_ERROR; - } - const chip::CommandId * endOfList = serverCluster->generatedCommandList; - while (*endOfList != kInvalidCommandId) - { - endOfList++; - } - const size_t commandCount = static_cast(endOfList - serverCluster->generatedCommandList); - result = DataModel::MetadataList::FromConstSpan({ serverCluster->generatedCommandList, commandCount }); - - return CHIP_NO_ERROR; -} - DataModel::ServerClusterEntry ServerClusterEntryFrom(EndpointId endpointId, const EmberAfCluster & cluster) { DataModel::ServerClusterEntry entry; @@ -350,21 +191,11 @@ std::optional CodegenDataModelProvider::Invoke(co return std::nullopt; } -DataModel::MetadataList CodegenDataModelProvider::Endpoints() +CHIP_ERROR CodegenDataModelProvider::Endpoints(DataModel::ListBuilder & builder) { - DataModel::MetadataList result; - const uint16_t endpointCount = emberAfEndpointCount(); - // allocate the max as some endpoints may be disabled - CHIP_ERROR err = result.Reserve(endpointCount); - if (err != CHIP_NO_ERROR) - { -#if CHIP_ERROR_LOGGING && CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to allocate space for endpoints: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - return {}; - } + ReturnErrorOnFailure(builder.EnsureAppendCapacity(endpointCount)); for (uint16_t endpointIndex = 0; endpointIndex < endpointCount; endpointIndex++) { @@ -387,18 +218,10 @@ DataModel::MetadataList CodegenDataModelProvider::Endp entry.compositionPattern = DataModel::EndpointCompositionPattern::kTree; break; } - - err = result.Append(entry); - if (err != CHIP_NO_ERROR) - { -#if CHIP_ERROR_LOGGING && CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to append endpoint data: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - break; - } + ReturnErrorOnFailure(builder.Append(entry)); } - return result; + return CHIP_NO_ERROR; } std::optional CodegenDataModelProvider::TryFindEndpointIndex(EndpointId id) const @@ -421,24 +244,16 @@ std::optional CodegenDataModelProvider::TryFindEndpointIndex(EndpointI return std::make_optional(idx); } -DataModel::MetadataList CodegenDataModelProvider::ServerClusters(EndpointId endpointId) +CHIP_ERROR CodegenDataModelProvider::ServerClusters(EndpointId endpointId, + DataModel::ListBuilder & builder) { const EmberAfEndpointType * endpoint = emberAfFindEndpointType(endpointId); - DataModel::MetadataList result; + VerifyOrReturnValue(endpoint != nullptr, CHIP_ERROR_NOT_FOUND); + VerifyOrReturnValue(endpoint->clusterCount > 0, CHIP_NO_ERROR); + VerifyOrReturnValue(endpoint->cluster != nullptr, CHIP_NO_ERROR); - VerifyOrReturnValue(endpoint != nullptr, result); - VerifyOrReturnValue(endpoint->clusterCount > 0, result); - VerifyOrReturnValue(endpoint->cluster != nullptr, result); - - CHIP_ERROR err = result.Reserve(emberAfClusterCountForEndpointType(endpoint, /* server = */ true)); - if (err != CHIP_NO_ERROR) - { -#if CHIP_ERROR_LOGGING && CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to reserve space for client clusters: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - return {}; - } + ReturnErrorOnFailure(builder.EnsureAppendCapacity(emberAfClusterCountForEndpointType(endpoint, /* server = */ true))); const EmberAfCluster * begin = endpoint->cluster; const EmberAfCluster * end = endpoint->cluster + endpoint->clusterCount; @@ -448,74 +263,43 @@ DataModel::MetadataList CodegenDataModelProvider: { continue; } - - err = result.Append(ServerClusterEntryFrom(endpointId, *cluster)); - if (err != CHIP_NO_ERROR) - { -#if CHIP_ERROR_LOGGING && CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to append server cluster entry: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - break; - } + ReturnErrorOnFailure(builder.Append(ServerClusterEntryFrom(endpointId, *cluster))); } - return result; + return CHIP_NO_ERROR; } -DataModel::MetadataList CodegenDataModelProvider::Attributes(const ConcreteClusterPath & path) +CHIP_ERROR CodegenDataModelProvider::Attributes(const ConcreteClusterPath & path, + DataModel::ListBuilder & builder) { const EmberAfCluster * cluster = FindServerCluster(path); - DataModel::MetadataList result; - - VerifyOrReturnValue(cluster != nullptr, result); - VerifyOrReturnValue(cluster->attributeCount > 0, result); - VerifyOrReturnValue(cluster->attributes != nullptr, result); + VerifyOrReturnValue(cluster != nullptr, CHIP_ERROR_NOT_FOUND); + VerifyOrReturnValue(cluster->attributeCount > 0, CHIP_NO_ERROR); + VerifyOrReturnValue(cluster->attributes != nullptr, CHIP_NO_ERROR); - CHIP_ERROR err = result.Reserve(cluster->attributeCount); - if (err != CHIP_NO_ERROR) - { -#if CHIP_ERROR_LOGGING && CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to reserve space for attributes: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - return {}; - } + // TODO: if ember would encode data in AttributeEntry form, we could reference things directly + ReturnErrorOnFailure(builder.EnsureAppendCapacity(cluster->attributeCount)); Span attributeSpan(cluster->attributes, cluster->attributeCount); for (auto & attribute : attributeSpan) { - err = result.Append(AttributeEntryFrom(path, attribute)); - if (err != CHIP_NO_ERROR) - { -#if CHIP_ERROR_LOGGING && CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to append attribute entry: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - break; - } + ReturnErrorOnFailure(builder.Append(AttributeEntryFrom(path, attribute))); } - return result; + return CHIP_NO_ERROR; } -DataModel::MetadataList CodegenDataModelProvider::ClientClusters(EndpointId endpointId) +CHIP_ERROR CodegenDataModelProvider::ClientClusters(EndpointId endpointId, DataModel::ListBuilder & builder) { const EmberAfEndpointType * endpoint = emberAfFindEndpointType(endpointId); - DataModel::MetadataList result; + VerifyOrReturnValue(endpoint != nullptr, CHIP_ERROR_NOT_FOUND); + VerifyOrReturnValue(endpoint->clusterCount > 0, CHIP_NO_ERROR); + VerifyOrReturnValue(endpoint->cluster != nullptr, CHIP_NO_ERROR); - VerifyOrReturnValue(endpoint != nullptr, result); - VerifyOrReturnValue(endpoint->clusterCount > 0, result); - VerifyOrReturnValue(endpoint->cluster != nullptr, result); - - CHIP_ERROR err = result.Reserve(emberAfClusterCountForEndpointType(endpoint, /* server = */ false)); - if (err != CHIP_NO_ERROR) - { -#if CHIP_ERROR_LOGGING && CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to reserve space for client clusters: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - return {}; - } + ReturnErrorOnFailure(builder.EnsureAppendCapacity(emberAfClusterCountForEndpointType(endpoint, /* server = */ false))); const EmberAfCluster * begin = endpoint->cluster; const EmberAfCluster * end = endpoint->cluster + endpoint->clusterCount; @@ -525,18 +309,10 @@ DataModel::MetadataList CodegenDataModelProvider::ClientClusters(Endp { continue; } - - err = result.Append(cluster->clusterId); - if (err != CHIP_NO_ERROR) - { -#if CHIP_ERROR_LOGGING && CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to append client cluster id: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - break; - } + ReturnErrorOnFailure(builder.Append(cluster->clusterId)); } - return result; + return CHIP_NO_ERROR; } const EmberAfCluster * CodegenDataModelProvider::FindServerCluster(const ConcreteClusterPath & path) @@ -557,37 +333,150 @@ const EmberAfCluster * CodegenDataModelProvider::FindServerCluster(const Concret return cluster; } -DataModel::MetadataList -CodegenDataModelProvider::AcceptedCommands(const ConcreteClusterPath & path) +CHIP_ERROR CodegenDataModelProvider::AcceptedCommands(const ConcreteClusterPath & path, + DataModel::ListBuilder & builder) { - DataModel::MetadataList result; + CommandHandlerInterface * interface = + CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(path.mEndpointId, path.mClusterId); + if (interface != nullptr) + { + size_t commandCount = 0; - [[maybe_unused]] CHIP_ERROR err = FetchAcceptedCommands(path, FindServerCluster(path), result); + CHIP_ERROR err = interface->EnumerateAcceptedCommands( + path, + [](CommandId id, void * context) -> Loop { + *reinterpret_cast(context) += 1; + return Loop::Continue; + }, + reinterpret_cast(&commandCount)); -#if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - if (err != CHIP_NO_ERROR) + if (err == CHIP_NO_ERROR) + { + using EnumerationData = struct + { + ConcreteCommandPath commandPath; + DataModel::ListBuilder * acceptedCommandList; + CHIP_ERROR processingError; + }; + + EnumerationData enumerationData; + enumerationData.commandPath = ConcreteCommandPath(path.mEndpointId, path.mClusterId, kInvalidCommandId); + enumerationData.processingError = CHIP_NO_ERROR; + enumerationData.acceptedCommandList = &builder; + + ReturnErrorOnFailure(builder.EnsureAppendCapacity(commandCount)); + + ReturnErrorOnFailure(interface->EnumerateAcceptedCommands( + path, + [](CommandId commandId, void * context) -> Loop { + auto input = reinterpret_cast(context); + input->commandPath.mCommandId = commandId; + CHIP_ERROR appendError = input->acceptedCommandList->Append(AcceptedCommandEntryFor(input->commandPath)); + if (appendError != CHIP_NO_ERROR) + { + input->processingError = appendError; + return Loop::Break; + } + return Loop::Continue; + }, + reinterpret_cast(&enumerationData))); + ReturnErrorOnFailure(enumerationData.processingError); + + // the two invocations MUST return the same sizes. + VerifyOrReturnError(builder.Size() == commandCount, CHIP_ERROR_INTERNAL); + return CHIP_NO_ERROR; + } + VerifyOrReturnError(err == CHIP_ERROR_NOT_IMPLEMENTED, err); + } + + const EmberAfCluster * serverCluster = FindServerCluster(path); + VerifyOrReturnError(serverCluster != nullptr, CHIP_ERROR_NOT_FOUND); + VerifyOrReturnError(serverCluster->acceptedCommandList != nullptr, CHIP_NO_ERROR); + + const chip::CommandId * endOfList = serverCluster->acceptedCommandList; + while (*endOfList != kInvalidCommandId) { - ChipLogError(DataManagement, "Failed to fetch accepted commands: %" CHIP_ERROR_FORMAT, err.Format()); + endOfList++; } -#endif + const auto commandCount = static_cast(endOfList - serverCluster->acceptedCommandList); + + // TODO: if ember would store command entries, we could simplify this code to use static data + ReturnErrorOnFailure(builder.EnsureAppendCapacity(commandCount)); - return result; + ConcreteCommandPath commandPath = ConcreteCommandPath(path.mEndpointId, path.mClusterId, kInvalidCommandId); + for (const chip::CommandId * p = serverCluster->acceptedCommandList; p != endOfList; p++) + { + commandPath.mCommandId = *p; + ReturnErrorOnFailure(builder.Append(AcceptedCommandEntryFor(commandPath))); + } + + return CHIP_NO_ERROR; } -DataModel::MetadataList CodegenDataModelProvider::GeneratedCommands(const ConcreteClusterPath & path) +CHIP_ERROR CodegenDataModelProvider::GeneratedCommands(const ConcreteClusterPath & path, + DataModel::ListBuilder & builder) { - DataModel::MetadataList result; + CommandHandlerInterface * interface = + CommandHandlerInterfaceRegistry::Instance().GetCommandHandler(path.mEndpointId, path.mClusterId); + if (interface != nullptr) + { + size_t commandCount = 0; - [[maybe_unused]] CHIP_ERROR err = FetchGeneratedCommands(path, FindServerCluster(path), result); + CHIP_ERROR err = interface->EnumerateGeneratedCommands( + path, + [](CommandId id, void * context) -> Loop { + *reinterpret_cast(context) += 1; + return Loop::Continue; + }, + reinterpret_cast(&commandCount)); -#if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - if (err != CHIP_NO_ERROR) - { - ChipLogError(DataManagement, "Failed to fetch generated commands: %" CHIP_ERROR_FORMAT, err.Format()); + if (err == CHIP_NO_ERROR) + { + ReturnErrorOnFailure(builder.EnsureAppendCapacity(commandCount)); + + using EnumerationData = struct + { + DataModel::ListBuilder * generatedCommandList; + CHIP_ERROR processingError; + }; + EnumerationData enumerationData; + enumerationData.processingError = CHIP_NO_ERROR; + enumerationData.generatedCommandList = &builder; + + ReturnErrorOnFailure(interface->EnumerateGeneratedCommands( + path, + [](CommandId id, void * context) -> Loop { + auto input = reinterpret_cast(context); + + CHIP_ERROR appendError = input->generatedCommandList->Append(id); + if (appendError != CHIP_NO_ERROR) + { + input->processingError = appendError; + return Loop::Break; + } + return Loop::Continue; + }, + reinterpret_cast(&enumerationData))); + ReturnErrorOnFailure(enumerationData.processingError); + + // the two invocations MUST return the same sizes. + VerifyOrReturnError(builder.Size() == commandCount, CHIP_ERROR_INTERNAL); + return CHIP_NO_ERROR; + } + VerifyOrReturnError(err == CHIP_ERROR_NOT_IMPLEMENTED, err); } -#endif - return result; + const EmberAfCluster * serverCluster = FindServerCluster(path); + VerifyOrReturnError(serverCluster != nullptr, CHIP_ERROR_NOT_FOUND); + VerifyOrReturnError(serverCluster->generatedCommandList != nullptr, CHIP_NO_ERROR); + + const chip::CommandId * endOfList = serverCluster->generatedCommandList; + while (*endOfList != kInvalidCommandId) + { + endOfList++; + } + const auto commandCount = static_cast(endOfList - serverCluster->generatedCommandList); + return builder.ReferenceExisting({ serverCluster->generatedCommandList, commandCount }); } void CodegenDataModelProvider::InitDataModelForTesting() @@ -596,7 +485,8 @@ void CodegenDataModelProvider::InitDataModelForTesting() InitDataModelHandler(); } -DataModel::MetadataList CodegenDataModelProvider::DeviceTypes(EndpointId endpointId) +CHIP_ERROR CodegenDataModelProvider::DeviceTypes(EndpointId endpointId, + DataModel::ListBuilder & builder) { std::optional endpoint_index = TryFindEndpointIndex(endpointId); if (!endpoint_index.has_value()) @@ -607,31 +497,17 @@ DataModel::MetadataList CodegenDataModelProvider::De CHIP_ERROR err = CHIP_NO_ERROR; Span deviceTypes = emberAfDeviceTypeListFromEndpointIndex(*endpoint_index, err); - DataModel::MetadataList result; - err = result.Reserve(deviceTypes.size()); - if (err != CHIP_NO_ERROR) - { -#if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to reserve device type buffer space: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - return {}; - } + ReturnErrorOnFailure(builder.EnsureAppendCapacity(deviceTypes.size())); + for (auto & entry : deviceTypes) { - err = result.Append(DeviceTypeEntryFromEmber(entry)); - if (err != CHIP_NO_ERROR) - { -#if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to append device type entry: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - break; - } + ReturnErrorOnFailure(builder.Append(DeviceTypeEntryFromEmber(entry))); } - return result; + return CHIP_NO_ERROR; } -DataModel::MetadataList CodegenDataModelProvider::SemanticTags(EndpointId endpointId) +CHIP_ERROR CodegenDataModelProvider::SemanticTags(EndpointId endpointId, DataModel::ListBuilder & builder) { DataModel::Provider::SemanticTag semanticTag; size_t count = 0; @@ -640,38 +516,16 @@ DataModel::MetadataList CodegenDataModelProvid { count++; } - DataModel::MetadataList result; - CHIP_ERROR err = result.Reserve(count); - if (err != CHIP_NO_ERROR) - { -#if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to reserve semantic tag buffer space: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - return {}; - } + ReturnErrorOnFailure(builder.EnsureAppendCapacity(count)); for (size_t idx = 0; idx < count; idx++) { - err = GetSemanticTagForEndpointAtIndex(endpointId, idx, semanticTag); - if (err != CHIP_NO_ERROR) - { -#if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to get semantic tag data: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - break; - } - err = result.Append(semanticTag); - if (err != CHIP_NO_ERROR) - { -#if CHIP_CONFIG_DATA_MODEL_EXTRA_LOGGING - ChipLogError(AppServer, "Failed to append semantic tag: %" CHIP_ERROR_FORMAT, err.Format()); -#endif - break; - } + ReturnErrorOnFailure(GetSemanticTagForEndpointAtIndex(endpointId, idx, semanticTag)); + ReturnErrorOnFailure(builder.Append(semanticTag)); } - return result; + return CHIP_NO_ERROR; } } // namespace app diff --git a/src/data-model-providers/codegen/CodegenDataModelProvider.h b/src/data-model-providers/codegen/CodegenDataModelProvider.h index d0bb369e3dd23f..764f5f74874673 100644 --- a/src/data-model-providers/codegen/CodegenDataModelProvider.h +++ b/src/data-model-providers/codegen/CodegenDataModelProvider.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -66,14 +67,15 @@ class CodegenDataModelProvider : public DataModel::Provider CommandHandler * handler) override; /// attribute tree iteration - DataModel::MetadataList GeneratedCommands(const ConcreteClusterPath & path) override; - DataModel::MetadataList AcceptedCommands(const ConcreteClusterPath & path) override; - DataModel::MetadataList SemanticTags(EndpointId endpointId) override; - DataModel::MetadataList DeviceTypes(EndpointId endpointId) override; - DataModel::MetadataList Endpoints() override; - DataModel::MetadataList ClientClusters(EndpointId endpointId) override; - DataModel::MetadataList ServerClusters(EndpointId endpointId) override; - DataModel::MetadataList Attributes(const ConcreteClusterPath & path) override; + CHIP_ERROR Endpoints(DataModel::ListBuilder & out) override; + CHIP_ERROR SemanticTags(EndpointId endpointId, DataModel::ListBuilder & builder) override; + CHIP_ERROR DeviceTypes(EndpointId endpointId, DataModel::ListBuilder & builder) override; + CHIP_ERROR ClientClusters(EndpointId endpointId, DataModel::ListBuilder & builder) override; + CHIP_ERROR ServerClusters(EndpointId endpointId, DataModel::ListBuilder & builder) override; + CHIP_ERROR GeneratedCommands(const ConcreteClusterPath & path, DataModel::ListBuilder & builder) override; + CHIP_ERROR AcceptedCommands(const ConcreteClusterPath & path, + DataModel::ListBuilder & builder) override; + CHIP_ERROR Attributes(const ConcreteClusterPath & path, DataModel::ListBuilder & builder) override; void Temporary_ReportAttributeChanged(const AttributePathParams & path) override; diff --git a/src/data-model-providers/codegen/tests/TestCodegenModelViaMocks.cpp b/src/data-model-providers/codegen/tests/TestCodegenModelViaMocks.cpp index 67aed7f1d16ab6..1045114b7f9b4c 100644 --- a/src/data-model-providers/codegen/tests/TestCodegenModelViaMocks.cpp +++ b/src/data-model-providers/codegen/tests/TestCodegenModelViaMocks.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -905,9 +906,13 @@ TEST_F(TestCodegenModelViaMocks, IterateOverEndpoints) CodegenDataModelProviderWithContext model; // This iteration relies on the hard-coding that occurs when mock_ember is used - DataModel::MetadataList endpoints = model.Endpoints(); + DataModel::ListBuilder endpointsBuilder; - ASSERT_EQ(endpoints.Size(), 3u); + ASSERT_EQ(model.Endpoints(endpointsBuilder), CHIP_NO_ERROR); + + auto endpoints = endpointsBuilder.TakeBuffer(); + + ASSERT_EQ(endpoints.size(), 3u); EXPECT_EQ(endpoints[0].id, kMockEndpoint1); EXPECT_EQ(endpoints[0].parentId, kInvalidEndpointId); @@ -929,12 +934,17 @@ TEST_F(TestCodegenModelViaMocks, IterateOverServerClusters) chip::Test::ResetVersion(); - EXPECT_TRUE(model.ServerClusters(kEndpointIdThatIsMissing).Empty()); - EXPECT_TRUE(model.ServerClusters(kInvalidEndpointId).Empty()); + DataModel::ListBuilder builder; + + EXPECT_NE(model.ServerClusters(kEndpointIdThatIsMissing, builder), CHIP_NO_ERROR); + EXPECT_TRUE(builder.IsEmpty()); + EXPECT_NE(model.ServerClusters(kInvalidEndpointId, builder), CHIP_NO_ERROR); + EXPECT_TRUE(builder.IsEmpty()); // mock endpoint 1 has 2 mock clusters: 1 and 2 - auto serverClusters = model.ServerClusters(kMockEndpoint1); - ASSERT_EQ(serverClusters.Size(), 2u); + EXPECT_EQ(model.ServerClusters(kMockEndpoint1, builder), CHIP_NO_ERROR); + auto serverClusters = builder.TakeBuffer(); + ASSERT_EQ(serverClusters.size(), 2u); EXPECT_EQ(serverClusters[0].clusterId, MockClusterId(1)); EXPECT_EQ(serverClusters[0].dataVersion, 0u); @@ -946,14 +956,16 @@ TEST_F(TestCodegenModelViaMocks, IterateOverServerClusters) chip::Test::BumpVersion(); - serverClusters = model.ServerClusters(kMockEndpoint1); - ASSERT_EQ(serverClusters.Size(), 2u); + EXPECT_EQ(model.ServerClusters(kMockEndpoint1, builder), CHIP_NO_ERROR); + serverClusters = builder.TakeBuffer(); + ASSERT_EQ(serverClusters.size(), 2u); EXPECT_EQ(serverClusters[0].dataVersion, 1u); EXPECT_EQ(serverClusters[1].dataVersion, 1u); // mock endpoint 3 has 4 mock clusters: 1 through 4 - serverClusters = model.ServerClusters(kMockEndpoint3); - ASSERT_EQ(serverClusters.Size(), 4u); + EXPECT_EQ(model.ServerClusters(kMockEndpoint3, builder), CHIP_NO_ERROR); + serverClusters = builder.TakeBuffer(); + ASSERT_EQ(serverClusters.size(), 4u); EXPECT_EQ(serverClusters[0].clusterId, MockClusterId(1)); EXPECT_EQ(serverClusters[1].clusterId, MockClusterId(2)); EXPECT_EQ(serverClusters[2].clusterId, MockClusterId(3)); @@ -965,20 +977,26 @@ TEST_F(TestCodegenModelViaMocks, IterateOverClientClusters) UseMockNodeConfig config(gTestNodeConfig); CodegenDataModelProviderWithContext model; - EXPECT_TRUE(model.ClientClusters(kEndpointIdThatIsMissing).Empty()); - EXPECT_TRUE(model.ClientClusters(kInvalidEndpointId).Empty()); + DataModel::ListBuilder builder; + + EXPECT_EQ(model.ClientClusters(kEndpointIdThatIsMissing, builder), CHIP_ERROR_NOT_FOUND); + EXPECT_TRUE(builder.IsEmpty()); + EXPECT_EQ(model.ClientClusters(kInvalidEndpointId, builder), CHIP_ERROR_NOT_FOUND); + EXPECT_TRUE(builder.IsEmpty()); // mock endpoint 1 has 2 mock client clusters: 3 and 4 - auto clientClusters = model.ClientClusters(kMockEndpoint1); + EXPECT_EQ(model.ClientClusters(kMockEndpoint1, builder), CHIP_NO_ERROR); + auto clientClusters = builder.TakeBuffer(); const ClusterId kExpectedClusters1[] = { MockClusterId(3), MockClusterId(4) }; - ASSERT_TRUE(clientClusters.GetSpanValidForLifetime().data_equal(Span(kExpectedClusters1))); + ASSERT_TRUE(clientClusters.data_equal(Span(kExpectedClusters1))); // mock endpoint 2 has 1 mock client clusters: 3(has server side at the same time) and 4 - clientClusters = model.ClientClusters(kMockEndpoint2); + EXPECT_EQ(model.ClientClusters(kMockEndpoint2, builder), CHIP_NO_ERROR); + clientClusters = builder.TakeBuffer(); const ClusterId kExpectedClusters2[] = { MockClusterId(3), MockClusterId(4) }; - ASSERT_TRUE(clientClusters.GetSpanValidForLifetime().data_equal(Span(kExpectedClusters2))); + ASSERT_TRUE(clientClusters.data_equal(Span(kExpectedClusters2))); } TEST_F(TestCodegenModelViaMocks, IterateOverAttributes) @@ -987,14 +1005,23 @@ TEST_F(TestCodegenModelViaMocks, IterateOverAttributes) CodegenDataModelProviderWithContext model; // invalid paths should return in "no more data" - ASSERT_TRUE(model.Attributes(ConcreteClusterPath(kEndpointIdThatIsMissing, MockClusterId(1))).Empty()); - ASSERT_TRUE(model.Attributes(ConcreteClusterPath(kInvalidEndpointId, MockClusterId(1))).Empty()); - ASSERT_TRUE(model.Attributes(ConcreteClusterPath(kMockEndpoint1, MockClusterId(10))).Empty()); - ASSERT_TRUE(model.Attributes(ConcreteClusterPath(kMockEndpoint1, kInvalidClusterId)).Empty()); + ASSERT_TRUE(model.AttributesIgnoreError(ConcreteClusterPath(kEndpointIdThatIsMissing, MockClusterId(1))).empty()); + ASSERT_TRUE(model.AttributesIgnoreError(ConcreteClusterPath(kInvalidEndpointId, MockClusterId(1))).empty()); + ASSERT_TRUE(model.AttributesIgnoreError(ConcreteClusterPath(kMockEndpoint1, MockClusterId(10))).empty()); + ASSERT_TRUE(model.AttributesIgnoreError(ConcreteClusterPath(kMockEndpoint1, kInvalidClusterId)).empty()); // should be able to iterate over valid paths - auto attributes = model.Attributes(ConcreteClusterPath(kMockEndpoint2, MockClusterId(2))); - ASSERT_EQ(attributes.Size(), 4u); + DataModel::ListBuilder builder; + + // invalid paths return errors + ASSERT_EQ(model.Attributes(ConcreteClusterPath(kEndpointIdThatIsMissing, MockClusterId(1)), builder), CHIP_ERROR_NOT_FOUND); + ASSERT_EQ(model.Attributes(ConcreteClusterPath(kInvalidEndpointId, MockClusterId(1)), builder), CHIP_ERROR_NOT_FOUND); + ASSERT_EQ(model.Attributes(ConcreteClusterPath(kMockEndpoint1, MockClusterId(10)), builder), CHIP_ERROR_NOT_FOUND); + ASSERT_EQ(model.Attributes(ConcreteClusterPath(kMockEndpoint1, kInvalidClusterId), builder), CHIP_ERROR_NOT_FOUND); + + EXPECT_EQ(model.Attributes(ConcreteClusterPath(kMockEndpoint2, MockClusterId(2)), builder), CHIP_NO_ERROR); + auto attributes = builder.TakeBuffer(); + ASSERT_EQ(attributes.size(), 4u); ASSERT_EQ(attributes[0].attributeId, ClusterRevision::Id); ASSERT_FALSE(attributes[0].flags.Has(AttributeQualityFlags::kListAttribute)); @@ -1070,15 +1097,29 @@ TEST_F(TestCodegenModelViaMocks, IterateOverAcceptedCommands) UseMockNodeConfig config(gTestNodeConfig); CodegenDataModelProviderWithContext model; + DataModel::ListBuilder builder; + // invalid paths should return in "no more data" - ASSERT_TRUE(model.AcceptedCommands(ConcreteClusterPath(kEndpointIdThatIsMissing, MockClusterId(1))).Empty()); - ASSERT_TRUE(model.AcceptedCommands(ConcreteClusterPath(kInvalidEndpointId, MockClusterId(1))).Empty()); - ASSERT_TRUE(model.AcceptedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(10))).Empty()); - ASSERT_TRUE(model.AcceptedCommands(ConcreteClusterPath(kMockEndpoint1, kInvalidClusterId)).Empty()); - - MetadataList cmds = - model.AcceptedCommands(ConcreteClusterPath(kMockEndpoint2, MockClusterId(2))); - ASSERT_EQ(cmds.Size(), 3u); + ASSERT_EQ(model.AcceptedCommands(ConcreteClusterPath(kEndpointIdThatIsMissing, MockClusterId(1)), builder), + CHIP_ERROR_NOT_FOUND); + ASSERT_TRUE(builder.IsEmpty()); + ASSERT_EQ(model.AcceptedCommands(ConcreteClusterPath(kInvalidEndpointId, MockClusterId(1)), builder), CHIP_ERROR_NOT_FOUND); + ASSERT_TRUE(builder.IsEmpty()); + ASSERT_EQ(model.AcceptedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(10)), builder), CHIP_ERROR_NOT_FOUND); + ASSERT_TRUE(builder.IsEmpty()); + ASSERT_EQ(model.AcceptedCommands(ConcreteClusterPath(kMockEndpoint1, kInvalidClusterId), builder), CHIP_ERROR_NOT_FOUND); + ASSERT_TRUE(builder.IsEmpty()); + + ASSERT_EQ(model.AcceptedCommands(ConcreteClusterPath(kMockEndpoint2, MockClusterId(2)), builder), CHIP_NO_ERROR); + ASSERT_EQ(builder.Size(), 3u); + + auto cmds = builder.TakeBuffer(); + + // took ownership + ASSERT_EQ(builder.Size(), 0u); + ASSERT_TRUE(builder.IsEmpty()); + + ASSERT_EQ(cmds.size(), 3u); ASSERT_EQ(cmds[0].commandId, 1u); ASSERT_EQ(cmds[1].commandId, 2u); ASSERT_EQ(cmds[2].commandId, 23u); @@ -1089,20 +1130,30 @@ TEST_F(TestCodegenModelViaMocks, IterateOverGeneratedCommands) UseMockNodeConfig config(gTestNodeConfig); CodegenDataModelProviderWithContext model; + DataModel::ListBuilder builder; + // invalid paths should return in "no more data" - ASSERT_TRUE(model.GeneratedCommands(ConcreteClusterPath(kEndpointIdThatIsMissing, MockClusterId(1))).Empty()); - ASSERT_TRUE(model.GeneratedCommands(ConcreteClusterPath(kInvalidEndpointId, MockClusterId(1))).Empty()); - ASSERT_TRUE(model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(10))).Empty()); - ASSERT_TRUE(model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint1, kInvalidClusterId)).Empty()); + ASSERT_EQ(model.GeneratedCommands(ConcreteClusterPath(kEndpointIdThatIsMissing, MockClusterId(1)), builder), + CHIP_ERROR_NOT_FOUND); + ASSERT_TRUE(builder.IsEmpty()); + ASSERT_EQ(model.GeneratedCommands(ConcreteClusterPath(kInvalidEndpointId, MockClusterId(1)), builder), CHIP_ERROR_NOT_FOUND); + ASSERT_TRUE(builder.IsEmpty()); + ASSERT_EQ(model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(10)), builder), CHIP_ERROR_NOT_FOUND); + ASSERT_TRUE(builder.IsEmpty()); + ASSERT_EQ(model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint1, kInvalidClusterId), builder), CHIP_ERROR_NOT_FOUND); + ASSERT_TRUE(builder.IsEmpty()); // should be able to iterate over valid paths - MetadataList cmds = model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint2, MockClusterId(2))); + ASSERT_EQ(model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint2, MockClusterId(2)), builder), CHIP_NO_ERROR); + auto cmds = builder.TakeBuffer(); + const CommandId expectedCommands2[] = { 2, 10 }; - ASSERT_TRUE(cmds.GetSpanValidForLifetime().data_equal(Span(expectedCommands2))); + ASSERT_TRUE(cmds.data_equal(Span(expectedCommands2))); - cmds = model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint2, MockClusterId(3))); + ASSERT_EQ(model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint2, MockClusterId(3)), builder), CHIP_NO_ERROR); + cmds = builder.TakeBuffer(); const CommandId expectedCommands3[] = { 4, 6 }; - ASSERT_TRUE(cmds.GetSpanValidForLifetime().data_equal(Span(expectedCommands3))); + ASSERT_TRUE(cmds.data_equal(Span(expectedCommands3))); } TEST_F(TestCodegenModelViaMocks, CommandHandlerInterfaceCommandHandling) @@ -1115,16 +1166,23 @@ TEST_F(TestCodegenModelViaMocks, CommandHandlerInterfaceCommandHandling) // Validate that these work CustomListCommandHandler handler(MakeOptional(kMockEndpoint1), MockClusterId(1)); + DataModel::ListBuilder generatedBuilder; + DataModel::ListBuilder acceptedBuilder; + // At this point, without overrides, there should be no accepted/generated commands - ASSERT_TRUE(model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))).Empty()); - ASSERT_TRUE(model.AcceptedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))).Empty()); + ASSERT_EQ(model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1)), generatedBuilder), CHIP_NO_ERROR); + ASSERT_TRUE(generatedBuilder.IsEmpty()); + ASSERT_EQ(model.AcceptedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1)), acceptedBuilder), CHIP_NO_ERROR); + ASSERT_TRUE(acceptedBuilder.IsEmpty()); handler.SetOverrideAccepted(true); handler.SetOverrideGenerated(true); // with overrides, the list is still empty ... - ASSERT_TRUE(model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))).Empty()); - ASSERT_TRUE(model.AcceptedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))).Empty()); + ASSERT_EQ(model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1)), generatedBuilder), CHIP_NO_ERROR); + ASSERT_TRUE(generatedBuilder.IsEmpty()); + ASSERT_EQ(model.AcceptedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1)), acceptedBuilder), CHIP_NO_ERROR); + ASSERT_TRUE(acceptedBuilder.IsEmpty()); // set some overrides handler.AcceptedVec().push_back(1234); @@ -1132,16 +1190,17 @@ TEST_F(TestCodegenModelViaMocks, CommandHandlerInterfaceCommandHandling) handler.GeneratedVec().push_back(33); - MetadataList acceptedCommands = - model.AcceptedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))); + ASSERT_EQ(model.AcceptedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1)), acceptedBuilder), CHIP_NO_ERROR); + auto acceptedCommands = acceptedBuilder.TakeBuffer(); - ASSERT_EQ(acceptedCommands.Size(), 2u); + ASSERT_EQ(acceptedCommands.size(), 2u); ASSERT_EQ(acceptedCommands[0].commandId, 1234u); ASSERT_EQ(acceptedCommands[1].commandId, 999u); - MetadataList generatedCommands = model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1))); + ASSERT_EQ(model.GeneratedCommands(ConcreteClusterPath(kMockEndpoint1, MockClusterId(1)), generatedBuilder), CHIP_NO_ERROR); + auto generatedCommands = generatedBuilder.TakeBuffer(); const CommandId expectedGeneratedCommands[] = { 33 }; - ASSERT_TRUE(generatedCommands.GetSpanValidForLifetime().data_equal(Span(expectedGeneratedCommands))); + ASSERT_TRUE(generatedCommands.data_equal(Span(expectedGeneratedCommands))); } TEST_F(TestCodegenModelViaMocks, ReadForInvalidGlobalAttributePath) @@ -2390,8 +2449,10 @@ TEST_F(TestCodegenModelViaMocks, DeviceTypeIteration) CodegenDataModelProviderWithContext model; // Mock endpoint 1 has 3 device types - auto deviceTypes = model.DeviceTypes(kMockEndpoint1); - ASSERT_EQ(deviceTypes.Size(), 3u); + DataModel::ListBuilder builder; + ASSERT_EQ(model.DeviceTypes(kMockEndpoint1, builder), CHIP_NO_ERROR); + auto deviceTypes = builder.TakeBuffer(); + ASSERT_EQ(deviceTypes.size(), 3u); const DeviceTypeEntry expected1[] = { { .deviceTypeId = kDeviceTypeId1, .deviceTypeRevision = kDeviceTypeId1Version }, @@ -2404,13 +2465,18 @@ TEST_F(TestCodegenModelViaMocks, DeviceTypeIteration) } // Mock endpoint 2 has 1 device types - deviceTypes = model.DeviceTypes(kMockEndpoint2); - ASSERT_EQ(deviceTypes.Size(), 1u); + ASSERT_TRUE(builder.IsEmpty()); // ownership taken above, we start fresh + ASSERT_EQ(model.DeviceTypes(kMockEndpoint2, builder), CHIP_NO_ERROR); + deviceTypes = builder.TakeBuffer(); + ASSERT_EQ(deviceTypes.size(), 1u); const DeviceTypeEntry expected2 = { .deviceTypeId = kDeviceTypeId2, .deviceTypeRevision = kDeviceTypeId2Version }; ASSERT_EQ(deviceTypes[0], expected2); // empty endpoint works - ASSERT_TRUE(model.DeviceTypes(kMockEndpoint3).Empty()); + ASSERT_TRUE(builder.IsEmpty()); // ownership taken above, we start fresh + ASSERT_EQ(model.DeviceTypes(kMockEndpoint3, builder), CHIP_NO_ERROR); + ASSERT_TRUE(builder.IsEmpty()); + ASSERT_TRUE(builder.TakeBuffer().empty()); } TEST_F(TestCodegenModelViaMocks, SemanticTagIteration) @@ -2418,11 +2484,18 @@ TEST_F(TestCodegenModelViaMocks, SemanticTagIteration) UseMockNodeConfig config(gTestNodeConfig); CodegenDataModelProviderWithContext model; - ASSERT_TRUE(model.SemanticTags(kMockEndpoint2).Empty()); + DataModel::ListBuilder builder; + ASSERT_EQ(model.SemanticTags(kMockEndpoint2, builder), CHIP_NO_ERROR); + ASSERT_TRUE(builder.IsEmpty()); + auto tags = builder.TakeBuffer(); + ASSERT_TRUE(tags.empty()); // Mock endpoint 1 has 3 semantic tags - MetadataList tags = model.SemanticTags(kMockEndpoint1); - ASSERT_EQ(tags.Size(), 3u); + ASSERT_EQ(model.SemanticTags(kMockEndpoint1, builder), CHIP_NO_ERROR); + ASSERT_EQ(builder.Size(), 3u); + tags = builder.TakeBuffer(); + ASSERT_EQ(tags.size(), 3u); + ASSERT_TRUE(builder.IsEmpty()); // ownership taken auto tag = tags[0]; EXPECT_EQ(tag.mfgCode, MakeNullable(VendorId::TestVendor1)); From 87de90d08f6fa0866cf7fd8b145028c7ea544bd8 Mon Sep 17 00:00:00 2001 From: Mathieu Kardous <84793247+mkardous-silabs@users.noreply.github.com> Date: Thu, 23 Jan 2025 16:43:58 -0500 Subject: [PATCH 18/40] [Silabs] Add provisioning root argument (#37175) * [SL-UP] Add provisioning root argument (#231) * Restyled by gn --------- Co-authored-by: Restyled.io --- examples/platform/silabs/SiWx917/BUILD.gn | 3 ++- examples/platform/silabs/efr32/BUILD.gn | 3 ++- examples/platform/silabs/provision/BUILD.gn | 4 ++-- src/platform/silabs/SiWx917/BUILD.gn | 6 +++++- src/platform/silabs/efr32/BUILD.gn | 3 ++- src/platform/silabs/provision/args.gni | 19 +++++++++++++++++++ src/test_driver/efr32/BUILD.gn | 3 ++- 7 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 src/platform/silabs/provision/args.gni diff --git a/examples/platform/silabs/SiWx917/BUILD.gn b/examples/platform/silabs/SiWx917/BUILD.gn index 69379c11ff621e..3087a5f64ba9b8 100644 --- a/examples/platform/silabs/SiWx917/BUILD.gn +++ b/examples/platform/silabs/SiWx917/BUILD.gn @@ -18,6 +18,7 @@ import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") import("${chip_root}/examples/platform/silabs/args.gni") import("${chip_root}/src/lib/lib.gni") import("${chip_root}/src/platform/device.gni") +import("${chip_root}/src/platform/silabs/provision/args.gni") import("${chip_root}/src/platform/silabs/wifi/args.gni") import("${chip_root}/third_party/silabs/silabs_board.gni") import("${silabs_sdk_build_root}/SiWx917_sdk.gni") @@ -67,7 +68,7 @@ source_set("test-event-trigger") { "${silabs_common_plat_dir}/SilabsTestEventTriggerDelegate.h", ] - deps = [ "${chip_root}/src/platform/silabs/provision:provision-headers" ] + deps = [ "${sl_provision_root}:provision-headers" ] public_configs = [ ":test-event-trigger-config" ] public_deps = [ "${chip_root}/src/app:test-event-trigger", diff --git a/examples/platform/silabs/efr32/BUILD.gn b/examples/platform/silabs/efr32/BUILD.gn index 6d41d79c087c82..8b54549ad64528 100644 --- a/examples/platform/silabs/efr32/BUILD.gn +++ b/examples/platform/silabs/efr32/BUILD.gn @@ -18,6 +18,7 @@ import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") import("${chip_root}/src/app/icd/icd.gni") import("${chip_root}/src/lib/lib.gni") import("${chip_root}/src/platform/device.gni") +import("${chip_root}/src/platform/silabs/provision/args.gni") import("${silabs_sdk_build_root}/efr32_sdk.gni") import("${silabs_sdk_build_root}/silabs_board.gni") @@ -71,7 +72,7 @@ source_set("test-event-trigger") { "${silabs_common_plat_dir}/SilabsTestEventTriggerDelegate.h", ] - deps = [ "${chip_root}/src/platform/silabs/provision:provision-headers" ] + deps = [ "${sl_provision_root}:provision-headers" ] public_configs = [ ":test-event-trigger-config" ] public_deps = [ "${chip_root}/src/app:test-event-trigger", diff --git a/examples/platform/silabs/provision/BUILD.gn b/examples/platform/silabs/provision/BUILD.gn index 517dd33c124e47..1ab4744a2e12e4 100644 --- a/examples/platform/silabs/provision/BUILD.gn +++ b/examples/platform/silabs/provision/BUILD.gn @@ -14,6 +14,7 @@ import("//build_overrides/chip.gni") import("//build_overrides/efr32_sdk.gni") +import("${chip_root}/src/platform/silabs/provision/args.gni") import("${silabs_sdk_build_root}/silabs_board.gni") if (wifi_soc) { @@ -48,8 +49,7 @@ source_set("storage") { deps = [ "${chip_root}/src/lib" ] - public_deps = - [ "${chip_root}/src/platform/silabs/provision:provision-headers" ] + public_deps = [ "${sl_provision_root}:provision-headers" ] if (sl_enable_test_event_trigger) { # Temporary workaround since we have duplicated configurations diff --git a/src/platform/silabs/SiWx917/BUILD.gn b/src/platform/silabs/SiWx917/BUILD.gn index 3f7adf8269c61b..bca3755f1decd1 100644 --- a/src/platform/silabs/SiWx917/BUILD.gn +++ b/src/platform/silabs/SiWx917/BUILD.gn @@ -18,6 +18,7 @@ import("${chip_root}/src/platform/device.gni") import("${chip_root}/build/chip/buildconfig_header.gni") import("${chip_root}/src/crypto/crypto.gni") +import("${chip_root}/src/platform/silabs/provision/args.gni") import("${chip_root}/src/platform/silabs/wifi/args.gni") import("${chip_root}/third_party/silabs/SiWx917_sdk.gni") import("${chip_root}/third_party/silabs/silabs_board.gni") @@ -87,7 +88,10 @@ static_library("SiWx917") { "${chip_root}/src/app/icd/server:icd-server-config", "${chip_root}/src/platform:platform_base", ] - deps = [ "${chip_root}/src/platform/logging:headers" ] + deps = [ + "${chip_root}/src/platform/logging:headers", + "${sl_provision_root}:provision-headers", + ] # Add platform crypto implementation if (chip_crypto == "platform") { diff --git a/src/platform/silabs/efr32/BUILD.gn b/src/platform/silabs/efr32/BUILD.gn index cee56ebe666f41..3102a4d924f494 100644 --- a/src/platform/silabs/efr32/BUILD.gn +++ b/src/platform/silabs/efr32/BUILD.gn @@ -17,6 +17,7 @@ import("//build_overrides/chip.gni") import("${chip_root}/build/chip/buildconfig_header.gni") import("${chip_root}/src/crypto/crypto.gni") import("${chip_root}/src/platform/device.gni") +import("${chip_root}/src/platform/silabs/provision/args.gni") import("${chip_root}/third_party/silabs/efr32_sdk.gni") import("${chip_root}/third_party/silabs/silabs_board.gni") @@ -114,7 +115,7 @@ static_library("efr32") { "${chip_root}/src/platform:platform_base", "${chip_root}/src/platform/logging:headers", ] - deps = [ "${silabs_platform_dir}/provision:provision-headers" ] + deps = [ "${sl_provision_root}:provision-headers" ] public_configs = [] # Add platform crypto implementation diff --git a/src/platform/silabs/provision/args.gni b/src/platform/silabs/provision/args.gni new file mode 100644 index 00000000000000..a92793192bed59 --- /dev/null +++ b/src/platform/silabs/provision/args.gni @@ -0,0 +1,19 @@ +# 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") + +declare_args() { + sl_provision_root = "${chip_root}/src/platform/silabs/provision" +} diff --git a/src/test_driver/efr32/BUILD.gn b/src/test_driver/efr32/BUILD.gn index dd1969a5acd256..1ff7a3a505c465 100644 --- a/src/test_driver/efr32/BUILD.gn +++ b/src/test_driver/efr32/BUILD.gn @@ -18,6 +18,7 @@ import("//build_overrides/efr32_sdk.gni") import("//build_overrides/pigweed.gni") import("${build_root}/config/defaults.gni") +import("${chip_root}/src/platform/silabs/provision/args.gni") import("${silabs_sdk_build_root}/efr32_sdk.gni") import("${chip_root}/examples/common/pigweed/pigweed_rpcs.gni") @@ -94,8 +95,8 @@ source_set("efr32_test_main") { "${chip_root}/examples/common/pigweed:system_rpc_server", "${chip_root}/src/lib", "${chip_root}/src/lib/support:pw_tests_wrapper", - "${chip_root}/src/platform/silabs/provision:provision-headers", "${examples_common_plat_dir}/pw_sys_io:pw_sys_io_silabs", + "${sl_provision_root}:provision-headers", ] # OpenThread Settings From 1ae6ad6b6644292894a2112f8980b18051786b64 Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:09:15 +1300 Subject: [PATCH 19/40] Darwin: Add a module map for Matter.framework marking it as system (#37165) This affects how NSUInteger is bridged into Swift when building locally. --- src/darwin/Framework/CHIP/Matter.modulemap | 5 +++++ src/darwin/Framework/Matter.xcodeproj/project.pbxproj | 4 ++++ 2 files changed, 9 insertions(+) create mode 100644 src/darwin/Framework/CHIP/Matter.modulemap diff --git a/src/darwin/Framework/CHIP/Matter.modulemap b/src/darwin/Framework/CHIP/Matter.modulemap new file mode 100644 index 00000000000000..d5159009463023 --- /dev/null +++ b/src/darwin/Framework/CHIP/Matter.modulemap @@ -0,0 +1,5 @@ +framework module Matter [system] { + umbrella header "Matter.h" + export * + module * { export * } +} diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj index 77cc1c03187bd9..40be3cfa2c9449 100644 --- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj +++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj @@ -802,6 +802,7 @@ 75B765BF2A1D70F80014719B /* MTRAttributeSpecifiedCheck-src.zapt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "MTRAttributeSpecifiedCheck-src.zapt"; sourceTree = ""; }; 75B765C02A1D71BC0014719B /* MTRAttributeSpecifiedCheck.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRAttributeSpecifiedCheck.h; sourceTree = ""; }; 75B765C22A1D82D30014719B /* MTRAttributeSpecifiedCheck.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRAttributeSpecifiedCheck.mm; sourceTree = ""; }; + 7CD490112D378CF4007F9145 /* Matter.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = Matter.modulemap; sourceTree = ""; }; 8874C1312B69C7060084BEFD /* MTRMetricsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRMetricsTests.m; sourceTree = ""; }; 88E07D602B9A89A4005FD53E /* MTRMetricKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRMetricKeys.h; sourceTree = ""; }; 88E6C9432B6334ED001A1FE0 /* MTRMetrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRMetrics.h; sourceTree = ""; }; @@ -1415,6 +1416,7 @@ B202528F2459E34F00F97062 /* CHIP */ = { isa = PBXGroup; children = ( + 7CD490112D378CF4007F9145 /* Matter.modulemap */, CF3B63CB2CA31E71003C1C87 /* MTROTAImageTransferHandler.h */, CF3B63CD2CA31E71003C1C87 /* MTROTAImageTransferHandler.mm */, CF3B63CC2CA31E71003C1C87 /* MTROTAUnsolicitedBDXMessageHandler.h */, @@ -2654,6 +2656,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LIBRARY_SEARCH_PATHS = "$(TEMP_DIR)/out/lib"; + MODULEMAP_FILE = CHIP/Matter.modulemap; OTHER_CFLAGS = "-fmacro-prefix-map=$(SRCROOT)/CHIP/="; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", @@ -2823,6 +2826,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 14.0; LIBRARY_SEARCH_PATHS = "$(TEMP_DIR)/out/lib"; + MODULEMAP_FILE = CHIP/Matter.modulemap; OTHER_CFLAGS = "-fmacro-prefix-map=$(SRCROOT)/CHIP/="; OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", From 8ec073130dc747d5b7d456038a9faa974aa4fdcb Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 23 Jan 2025 20:38:26 -0500 Subject: [PATCH 20/40] Add Matter.framwework logging for invoke work items that exceed timed invoke timeout. (#37179) We should log what happened to the work item, not just silently complete it. --- src/darwin/Framework/CHIP/MTRDevice_Concrete.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm index 264a268e253163..e4937b2d64f990 100644 --- a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm +++ b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm @@ -3265,6 +3265,7 @@ - (void)_invokeCommandWithEndpointID:(NSNumber *)endpointID if ([now compare:cutoffTime] == NSOrderedDescending) { // Our timed invoke timeout has expired already. Command // was queued for too long. Do not send it out. + MTR_LOG("Invoke work item [%llu] timed out its timed invoke timeout before being dispatched", workItemID); workDone(nil, [MTRError errorForIMStatusCode:Status::Timeout]); return; } From 2376bddf43748f46f2f1fe36cc950583c6ddb1d3 Mon Sep 17 00:00:00 2001 From: Jeff Tung <100387939+jtung-apple@users.noreply.github.com> Date: Thu, 23 Jan 2025 21:22:54 -0800 Subject: [PATCH 21/40] [Darwin] On resubscribe attempt, if no need to subscribe, clear subsc ription work (#37177) --- src/darwin/Framework/CHIP/MTRDevice_Concrete.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm index e4937b2d64f990..cb92e52a1dac9f 100644 --- a/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm +++ b/src/darwin/Framework/CHIP/MTRDevice_Concrete.mm @@ -1487,6 +1487,7 @@ - (void)_reattemptSubscriptionNowIfNeededWithReason:(NSString *)reason os_unfair_lock_assert_owner(&self->_lock); if (!self.reattemptingSubscription) { + [self _clearSubscriptionPoolWork]; return; } From 7f32ff8a90cd243e19f2c63d122103058af6506b Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Fri, 24 Jan 2025 18:26:20 +1300 Subject: [PATCH 22/40] Darwin: Add MTRCommissioningParameters.readEndpointInformation (#37118) * Darwin: Tidy up some device type meta-data classes - Move MTRDeviceTypeRevision out of ServerEndpoint directory - Move MTRProductIdentity into its own file - Implement NSCopying and equality on MTRDeviceType and MTRProductIdentity - Implement description on all 3 types - Add tests * Darwin: Add MTRCommissioningParameters.readEndpointInformation Endpoint information is made availalable to the delegate via an MTRCommissioneeInfo object containing MTREndpointInfo objects. * Apply suggestions from code review Co-authored-by: Boris Zbarsky * Use NSString literal for MTRDeviceTypeData * Process endpoints in best-effort fashion even with invalid / missing DeviceTypeList Also add some additional comments to parsing logic and a couple more tests. * Address further review comments for Darwin layer * Move MTRCommissioneeInfo into its own set of files * Make MTRCommissioneeInfo and related types conform to NSSecureCoding Also conform to NSCopying, mark as sendable, and implement isEqual/hash. * Fix terminology a bit. --------- Co-authored-by: Boris Zbarsky --- .../MTRAttributeTLVValueDecoder_Internal.h | 13 +- .../MTRAttributeTLVValueDecoder_Internal.mm | 34 +++ .../Framework/CHIP/MTRCommissioneeInfo.h | 52 ++++ .../Framework/CHIP/MTRCommissioneeInfo.mm | 95 +++++++ .../CHIP/MTRCommissioneeInfo_Internal.h | 32 +++ .../CHIP/MTRCommissioningParameters.h | 9 +- .../Framework/CHIP/MTRDefines_Internal.h | 6 +- .../Framework/CHIP/MTRDeviceController.mm | 11 +- .../CHIP/MTRDeviceControllerDelegate.h | 38 ++- .../CHIP/MTRDeviceControllerDelegateBridge.mm | 48 ++-- .../CHIP/MTRDeviceController_Concrete.mm | 7 +- src/darwin/Framework/CHIP/MTRDeviceType.h | 9 +- src/darwin/Framework/CHIP/MTRDeviceType.mm | 65 ++++- .../Framework/CHIP/MTRDeviceTypeMetadata.h | 8 +- .../MTRDeviceTypeRevision.h | 20 +- .../MTRDeviceTypeRevision.mm | 58 +++- src/darwin/Framework/CHIP/MTREndpointInfo.h | 48 ++++ src/darwin/Framework/CHIP/MTREndpointInfo.mm | 269 ++++++++++++++++++ .../Framework/CHIP/MTREndpointInfo_Internal.h | 48 ++++ .../Framework/CHIP/MTREndpointInfo_Test.h | 38 +++ .../CHIP/MTROperationalCredentialsDelegate.h | 12 +- .../Framework/CHIP/MTRProductIdentity.h | 42 +++ .../Framework/CHIP/MTRProductIdentity.mm | 95 +++++++ src/darwin/Framework/CHIP/Matter.h | 3 + .../templates/MTRDeviceTypeMetadata-src.zapt | 6 +- .../zap-generated/MTRDeviceTypeMetadata.mm | 144 +++++----- .../CHIPTests/MTRDeviceTypeRevisionTests.m | 96 +++++++ .../Framework/CHIPTests/MTRDeviceTypeTests.m | 25 +- .../CHIPTests/MTREndpointInfoTests.m | 201 +++++++++++++ .../Framework/CHIPTests/MTRPairingTests.m | 79 ++++- .../CHIPTests/MTRProductIdentityTests.m | 64 +++++ .../Matter.xcodeproj/project.pbxproj | 56 +++- 32 files changed, 1543 insertions(+), 188 deletions(-) create mode 100644 src/darwin/Framework/CHIP/MTRAttributeTLVValueDecoder_Internal.mm create mode 100644 src/darwin/Framework/CHIP/MTRCommissioneeInfo.h create mode 100644 src/darwin/Framework/CHIP/MTRCommissioneeInfo.mm create mode 100644 src/darwin/Framework/CHIP/MTRCommissioneeInfo_Internal.h rename src/darwin/Framework/CHIP/{ServerEndpoint => }/MTRDeviceTypeRevision.h (69%) rename src/darwin/Framework/CHIP/{ServerEndpoint => }/MTRDeviceTypeRevision.mm (60%) create mode 100644 src/darwin/Framework/CHIP/MTREndpointInfo.h create mode 100644 src/darwin/Framework/CHIP/MTREndpointInfo.mm create mode 100644 src/darwin/Framework/CHIP/MTREndpointInfo_Internal.h create mode 100644 src/darwin/Framework/CHIP/MTREndpointInfo_Test.h create mode 100644 src/darwin/Framework/CHIP/MTRProductIdentity.h create mode 100644 src/darwin/Framework/CHIP/MTRProductIdentity.mm create mode 100644 src/darwin/Framework/CHIPTests/MTRDeviceTypeRevisionTests.m create mode 100644 src/darwin/Framework/CHIPTests/MTREndpointInfoTests.m create mode 100644 src/darwin/Framework/CHIPTests/MTRProductIdentityTests.m diff --git a/src/darwin/Framework/CHIP/MTRAttributeTLVValueDecoder_Internal.h b/src/darwin/Framework/CHIP/MTRAttributeTLVValueDecoder_Internal.h index a9adc87bb76f2b..22d50cf515578e 100644 --- a/src/darwin/Framework/CHIP/MTRAttributeTLVValueDecoder_Internal.h +++ b/src/darwin/Framework/CHIP/MTRAttributeTLVValueDecoder_Internal.h @@ -1,6 +1,5 @@ -/* - * - * Copyright (c) 2021 Project CHIP Authors +/** + * Copyright (c) 2021-2024 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,17 +15,21 @@ * limitations under the License. */ -#pragma once - #import +#include #include #include #include NS_ASSUME_NONNULL_BEGIN +// Decodes an attribute value TLV into a typed ObjC value (see MTRStructsObjc.h) id _Nullable MTRDecodeAttributeValue(const chip::app::ConcreteAttributePath & aPath, chip::TLV::TLVReader & aReader, CHIP_ERROR * aError); +// Wrapper around the precending function that reads the attribute from a ClusterStateCache. +id _Nullable MTRDecodeAttributeValue(const chip::app::ConcreteAttributePath & aPath, const chip::app::ClusterStateCache & aCache, + CHIP_ERROR * aError); + NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRAttributeTLVValueDecoder_Internal.mm b/src/darwin/Framework/CHIP/MTRAttributeTLVValueDecoder_Internal.mm new file mode 100644 index 00000000000000..d92da2f088aaa5 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRAttributeTLVValueDecoder_Internal.mm @@ -0,0 +1,34 @@ +/** + * 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 "MTRAttributeTLVValueDecoder_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +using namespace chip; + +id _Nullable MTRDecodeAttributeValue(const chip::app::ConcreteAttributePath & aPath, + const chip::app::ClusterStateCache & aCache, + CHIP_ERROR * aError) +{ + TLV::TLVReader reader; + *aError = aCache.Get(aPath, reader); + VerifyOrReturnValue(*aError == CHIP_NO_ERROR, nil); + return MTRDecodeAttributeValue(aPath, reader, aError); +} + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRCommissioneeInfo.h b/src/darwin/Framework/CHIP/MTRCommissioneeInfo.h new file mode 100644 index 00000000000000..7c6ff4daea435e --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRCommissioneeInfo.h @@ -0,0 +1,52 @@ +/** + * 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. + */ + +#import + +@class MTRProductIdentity; +@class MTREndpointInfo; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Information read from the commissionee device during commissioning. + */ +NS_SWIFT_SENDABLE +MTR_NEWLY_AVAILABLE +@interface MTRCommissioneeInfo : NSObject + +/** + * The product identity (VID / PID) of the commissionee. + */ +@property (nonatomic, copy, readonly) MTRProductIdentity * productIdentity; + +/** + * Endpoint information for all endpoints of the commissionee. + * Will be present only if readEndpointInformation is set to YES on MTRCommissioningParameters. + * + * Use `rootEndpoint` and `-[MTREndpointInfo children]` to traverse endpoints in composition order. + */ +@property (nonatomic, copy, readonly, nullable) NSDictionary * endpointsById; + +/** + * Endpoint information for the root endpoint of the commissionee. + * Will be present only if readEndpointInformation is set to YES on MTRCommissioningParameters. + */ +@property (nonatomic, copy, readonly, nullable) MTREndpointInfo * rootEndpoint; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRCommissioneeInfo.mm b/src/darwin/Framework/CHIP/MTRCommissioneeInfo.mm new file mode 100644 index 00000000000000..045697649e03fd --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRCommissioneeInfo.mm @@ -0,0 +1,95 @@ +/** + * 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. + */ + +#import "MTRCommissioneeInfo_Internal.h" + +#import "MTRDefines_Internal.h" +#import "MTREndpointInfo_Internal.h" +#import "MTRProductIdentity.h" +#import "MTRUtilities.h" + +NS_ASSUME_NONNULL_BEGIN + +MTR_DIRECT_MEMBERS +@implementation MTRCommissioneeInfo + +- (instancetype)initWithCommissioningInfo:(const chip::Controller::ReadCommissioningInfo &)info +{ + self = [super init]; + _productIdentity = [[MTRProductIdentity alloc] initWithVendorID:@(info.basic.vendorId) productID:@(info.basic.productId)]; + + // TODO: We should probably hold onto our MTRCommissioningParameters so we can look at `readEndpointInformation` + // instead of just reading whatever Descriptor cluster information happens to be in the cache. + auto * endpoints = [MTREndpointInfo endpointsFromAttributeCache:info.attributes]; + if (endpoints.count > 0) { + _endpointsById = endpoints; + } + + return self; +} + +static NSString * const sProductIdentityCodingKey = @"pi"; +static NSString * const sEndpointsCodingKey = @"ep"; + +- (nullable instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super init]; + _productIdentity = [coder decodeObjectOfClass:MTRProductIdentity.class forKey:sProductIdentityCodingKey]; + VerifyOrReturnValue(_productIdentity != nil, nil); + _endpointsById = [coder decodeDictionaryWithKeysOfClass:NSNumber.class + objectsOfClass:MTREndpointInfo.class + forKey:sEndpointsCodingKey]; + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeObject:_productIdentity forKey:sProductIdentityCodingKey]; + [coder encodeObject:_endpointsById forKey:sEndpointsCodingKey]; +} + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (NSUInteger)hash +{ + return _productIdentity.hash; +} + +- (BOOL)isEqual:(id)object +{ + VerifyOrReturnValue([object class] == [self class], NO); + MTRCommissioneeInfo * other = object; + VerifyOrReturnValue(MTREqualObjects(_productIdentity, other->_productIdentity), NO); + VerifyOrReturnValue(MTREqualObjects(_endpointsById, other->_endpointsById), NO); + return YES; +} + +- (id)copyWithZone:(nullable NSZone *)zone +{ + return self; // immutable +} + +- (nullable MTREndpointInfo *)rootEndpoint +{ + return self.endpointsById[@0]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRCommissioneeInfo_Internal.h b/src/darwin/Framework/CHIP/MTRCommissioneeInfo_Internal.h new file mode 100644 index 00000000000000..f892c5f64d01e0 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRCommissioneeInfo_Internal.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. + */ + +#import + +#import "MTRDefines_Internal.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +MTR_DIRECT_MEMBERS +@interface MTRCommissioneeInfo () + +- (instancetype)initWithCommissioningInfo:(const chip::Controller::ReadCommissioningInfo &)info; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRCommissioningParameters.h b/src/darwin/Framework/CHIP/MTRCommissioningParameters.h index 771dfe54fc8893..3dcd1efc53dcac 100644 --- a/src/darwin/Framework/CHIP/MTRCommissioningParameters.h +++ b/src/darwin/Framework/CHIP/MTRCommissioningParameters.h @@ -1,6 +1,5 @@ /** - * - * Copyright (c) 2022-2023 Project CHIP Authors + * Copyright (c) 2022-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. @@ -97,6 +96,12 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) */ @property (nonatomic, copy, nullable) NSString * countryCode MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)); +/** + * Read device type information from all endpoints during commissioning. + * Defaults to NO. + */ +@property (nonatomic, assign) BOOL readEndpointInformation MTR_NEWLY_AVAILABLE; + @end @interface MTRCommissioningParameters (Deprecated) diff --git a/src/darwin/Framework/CHIP/MTRDefines_Internal.h b/src/darwin/Framework/CHIP/MTRDefines_Internal.h index ba7d6be51d61f5..a93be2e6cf6f79 100644 --- a/src/darwin/Framework/CHIP/MTRDefines_Internal.h +++ b/src/darwin/Framework/CHIP/MTRDefines_Internal.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2023-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. @@ -30,8 +30,12 @@ #ifdef DEBUG #define MTR_TESTABLE MTR_EXPORT +#define MTR_TESTABLE_DIRECT +#define MTR_TESTABLE_DIRECT_MEMBERS #else #define MTR_TESTABLE +#define MTR_TESTABLE_DIRECT MTR_DIRECT +#define MTR_TESTABLE_DIRECT_MEMBERS MTR_DIRECT_MEMBERS #endif // clang-format off diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index 3b222a1e3eccfc..2380a5af846ff1 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -1,6 +1,5 @@ /** - * - * Copyright (c) 2020-2023 Project CHIP Authors + * Copyright (c) 2020-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. @@ -656,11 +655,13 @@ - (void)controller:(MTRDeviceController *)controller } logString:__PRETTY_FUNCTION__]; } -- (void)controller:(MTRDeviceController *)controller readCommissioningInfo:(MTRProductIdentity *)info +- (void)controller:(MTRDeviceController *)controller readCommissioneeInfo:(MTRCommissioneeInfo *)info { [self _callDelegatesWithBlock:^(id delegate) { - if ([delegate respondsToSelector:@selector(controller:readCommissioningInfo:)]) { - [delegate controller:controller readCommissioningInfo:info]; + if ([delegate respondsToSelector:@selector(controller:readCommissioneeInfo:)]) { + [delegate controller:controller readCommissioneeInfo:info]; + } else if ([delegate respondsToSelector:@selector(controller:readCommissioningInfo:)]) { + [delegate controller:controller readCommissioningInfo:info.productIdentity]; } } logString:__PRETTY_FUNCTION__]; } diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerDelegate.h b/src/darwin/Framework/CHIP/MTRDeviceControllerDelegate.h index bd575e5a42def3..5fac4483671744 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerDelegate.h +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerDelegate.h @@ -1,6 +1,5 @@ /** - * - * Copyright (c) 2020-2023 Project CHIP Authors + * Copyright (c) 2020-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. @@ -20,6 +19,13 @@ NS_ASSUME_NONNULL_BEGIN +@class MTRCommissioneeInfo; +@class MTRDeviceController; +@class MTRDeviceTypeRevision; +@class MTREndpointInfo; +@class MTRMetrics; +@class MTRProductIdentity; + typedef NS_ENUM(NSInteger, MTRCommissioningStatus) { MTRCommissioningStatusUnknown = 0, MTRCommissioningStatusSuccess = 1, @@ -29,22 +35,6 @@ typedef NS_ENUM(NSInteger, MTRCommissioningStatus) { = 3, } MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)); -/** - * A representation of a (vendor, product) pair that identifies a specific product. - */ -MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) -@interface MTRProductIdentity : NSObject - -@property (nonatomic, copy, readonly) NSNumber * vendorID; - -@property (nonatomic, copy, readonly) NSNumber * productID; - -- (instancetype)initWithVendorID:(NSNumber *)vendorID productID:(NSNumber *)productID; -@end - -@class MTRDeviceController; -@class MTRMetrics; - /** * The protocol definition for the MTRDeviceControllerDelegate. * @@ -98,14 +88,18 @@ MTR_AVAILABLE(ios(16.4), macos(13.3), watchos(9.4), tvos(16.4)) metrics:(MTRMetrics *)metrics MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)); /** - * Notify the delegate when commissioning infomation has been read from the Basic - * Information cluster of the commissionee. + * Notify the delegate when commissioning infomation has been read from the commissionee. * - * At the point when this notification happens, device attestation has not been performed yet, + * Note that this notification happens before device attestation is performed, * so the information delivered by this notification should not be trusted. */ - (void)controller:(MTRDeviceController *)controller - readCommissioningInfo:(MTRProductIdentity *)info MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)); + readCommissioneeInfo:(MTRCommissioneeInfo *)info MTR_NEWLY_AVAILABLE; + +- (void)controller:(MTRDeviceController *)controller + readCommissioningInfo:(MTRProductIdentity *)info + MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) + MTR_NEWLY_DEPRECATED("Use controller:readCommissioneeInfo:"); /** * Notify the delegate when the suspended state changed of the controller, after this happens diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm b/src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm index f19306eb7b67d0..33e678665499c0 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerDelegateBridge.mm @@ -1,6 +1,5 @@ /** - * - * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2020-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. @@ -16,12 +15,17 @@ */ #import "MTRDeviceControllerDelegateBridge.h" + +#import "MTRCommissioneeInfo_Internal.h" #import "MTRDeviceController.h" #import "MTRDeviceController_Internal.h" +#import "MTREndpointInfo_Internal.h" #import "MTRError_Internal.h" #import "MTRLogging_Internal.h" #import "MTRMetricKeys.h" #import "MTRMetricsCollector.h" +#import "MTRProductIdentity.h" +#import "MTRUtilities.h" using namespace chip::Tracing::DarwinFramework; @@ -124,20 +128,21 @@ void MTRDeviceControllerDelegateBridge::OnReadCommissioningInfo(const chip::Controller::ReadCommissioningInfo & info) { MTRDeviceController * strongController = mController; - - chip::VendorId vendorId = info.basic.vendorId; - uint16_t productId = info.basic.productId; - - MTR_LOG("%@ DeviceControllerDelegate Read Commissioning Info. VendorId %u ProductId %u", strongController, vendorId, productId); - id strongDelegate = mDelegate; - if (strongDelegate && mQueue && strongController) { - if ([strongDelegate respondsToSelector:@selector(controller:readCommissioningInfo:)]) { - dispatch_async(mQueue, ^{ - auto * info = [[MTRProductIdentity alloc] initWithVendorID:@(vendorId) productID:@(productId)]; - [strongDelegate controller:strongController readCommissioningInfo:info]; - }); - } + VerifyOrReturn(strongDelegate && mQueue && strongController); + + // TODO: These checks are pointless since currently mController == mDelegate + BOOL wantCommissioneeInfo = [strongDelegate respondsToSelector:@selector(controller:readCommissioneeInfo:)]; + BOOL wantProductIdentity = [strongDelegate respondsToSelector:@selector(controller:readCommissioningInfo:)]; + if (wantCommissioneeInfo || wantProductIdentity) { + auto * commissioneeInfo = [[MTRCommissioneeInfo alloc] initWithCommissioningInfo:info]; + dispatch_async(mQueue, ^{ + if (wantCommissioneeInfo) { // prefer the newer delegate method over the deprecated one + [strongDelegate controller:strongController readCommissioneeInfo:commissioneeInfo]; + } else if (wantProductIdentity) { + [strongDelegate controller:strongController readCommissioningInfo:commissioneeInfo.productIdentity]; + } + }); } } @@ -187,16 +192,3 @@ { mDeviceNodeId = deviceNodeId; } - -@implementation MTRProductIdentity - -- (instancetype)initWithVendorID:(NSNumber *)vendorID productID:(NSNumber *)productID -{ - if (self = [super init]) { - _vendorID = vendorID; - _productID = productID; - } - return self; -} - -@end diff --git a/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm b/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm index b27844425baa50..b67b07e8b81ba3 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm @@ -1,6 +1,5 @@ /** - * - * Copyright (c) 2020-2023 Project CHIP Authors + * Copyright (c) 2020-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. @@ -34,6 +33,7 @@ #import "MTRDeviceController_Concrete.h" #import "MTRDevice_Concrete.h" #import "MTRDevice_Internal.h" +#import "MTREndpointInfo_Internal.h" #import "MTRError_Internal.h" #import "MTRKeypair.h" #import "MTRLogging_Internal.h" @@ -961,6 +961,9 @@ - (BOOL)commissionNodeWithID:(NSNumber *)nodeID auto block = ^BOOL { chip::Controller::CommissioningParameters params; + if (commissioningParams.readEndpointInformation) { + params.SetExtraReadPaths(MTREndpointInfo.requiredAttributePaths); + } if (commissioningParams.csrNonce) { params.SetCSRNonce(AsByteSpan(commissioningParams.csrNonce)); } diff --git a/src/darwin/Framework/CHIP/MTRDeviceType.h b/src/darwin/Framework/CHIP/MTRDeviceType.h index 0330b76d1533a2..54802a19e12dd6 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceType.h +++ b/src/darwin/Framework/CHIP/MTRDeviceType.h @@ -23,8 +23,11 @@ NS_ASSUME_NONNULL_BEGIN +/** + * Meta-data about a device type defined in the Matter specification. + */ MTR_AVAILABLE(ios(18.2), macos(15.2), watchos(11.2), tvos(18.2)) -@interface MTRDeviceType : NSObject +@interface MTRDeviceType : NSObject /* (see below) */ /** * Returns an MTRDeviceType for the given ID, if the ID is known. Returns nil @@ -52,4 +55,8 @@ MTR_AVAILABLE(ios(18.2), macos(15.2), watchos(11.2), tvos(18.2)) @end +MTR_NEWLY_AVAILABLE +@interface MTRDeviceType () +@end + NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRDeviceType.mm b/src/darwin/Framework/CHIP/MTRDeviceType.mm index 394640d2d72b2a..3fb9b7aa033b68 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceType.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceType.mm @@ -17,27 +17,44 @@ #import +#import "MTRDefines_Internal.h" #import "MTRDeviceTypeMetadata.h" #import "MTRLogging_Internal.h" +#include #include +NS_ASSUME_NONNULL_BEGIN + using namespace chip; -@implementation MTRDeviceType +MTR_DIRECT_MEMBERS +@implementation MTRDeviceType { + const MTRDeviceTypeData * _meta; +} -- (nullable instancetype)initWithDeviceTypeID:(NSNumber *)id name:(NSString *)name isUtility:(BOOL)isUtility +- (instancetype)initWithDeviceTypeData:(const MTRDeviceTypeData *)metaData { - if (!(self = [super init])) { - return nil; - } - - _id = id; - _name = name; - _isUtility = isUtility; + self = [super init]; + _meta = metaData; return self; } +- (NSNumber *)id +{ + return @(_meta->id); +} + +- (NSString *)name +{ + return _meta->name; +} + +- (BOOL)isUtility +{ + return _meta->deviceClass != MTRDeviceTypeClass::Simple; +} + + (nullable MTRDeviceType *)deviceTypeForID:(NSNumber *)deviceTypeID { if (!CanCastTo(deviceTypeID.unsignedLongLongValue)) { @@ -50,10 +67,32 @@ + (nullable MTRDeviceType *)deviceTypeForID:(NSNumber *)deviceTypeID return nil; } - return [[MTRDeviceType alloc] - initWithDeviceTypeID:deviceTypeID - name:[NSString stringWithUTF8String:deviceTypeData->name] - isUtility:(deviceTypeData->deviceClass != MTRDeviceTypeClass::Simple)]; + return [[MTRDeviceType alloc] initWithDeviceTypeData:deviceTypeData]; +} + +- (id)copyWithZone:(nullable NSZone *)zone +{ + return self; // immutable +} + +- (NSUInteger)hash +{ + return _meta->id; +} + +- (BOOL)isEqual:(id)object +{ + VerifyOrReturnValue([object class] == [self class], NO); + MTRDeviceType * other = object; + return _meta->id == other->_meta->id; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@ 0x%" PRIx32 " (%@)>", + self.class, _meta->id, _meta->name]; } @end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRDeviceTypeMetadata.h b/src/darwin/Framework/CHIP/MTRDeviceTypeMetadata.h index 2597f60ec47415..b0f1a280532756 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceTypeMetadata.h +++ b/src/darwin/Framework/CHIP/MTRDeviceTypeMetadata.h @@ -23,18 +23,16 @@ NS_ASSUME_NONNULL_BEGIN -enum class MTRDeviceTypeClass -{ +enum class MTRDeviceTypeClass { Utility, Simple, Node, // Might not be a real class, but we have it for Root Node for now. }; -struct MTRDeviceTypeData -{ +struct MTRDeviceTypeData { chip::DeviceTypeId id; MTRDeviceTypeClass deviceClass; - const char * name; + NSString * name; }; // Returns null for unknown device types. diff --git a/src/darwin/Framework/CHIP/ServerEndpoint/MTRDeviceTypeRevision.h b/src/darwin/Framework/CHIP/MTRDeviceTypeRevision.h similarity index 69% rename from src/darwin/Framework/CHIP/ServerEndpoint/MTRDeviceTypeRevision.h rename to src/darwin/Framework/CHIP/MTRDeviceTypeRevision.h index 517948816364c2..e5e55a56450c95 100644 --- a/src/darwin/Framework/CHIP/ServerEndpoint/MTRDeviceTypeRevision.h +++ b/src/darwin/Framework/CHIP/MTRDeviceTypeRevision.h @@ -17,6 +17,9 @@ #import #import +@class MTRDescriptorClusterDeviceTypeStruct; +@class MTRDeviceType; + NS_ASSUME_NONNULL_BEGIN /** @@ -25,7 +28,7 @@ NS_ASSUME_NONNULL_BEGIN */ NS_SWIFT_SENDABLE MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) -@interface MTRDeviceTypeRevision : NSObject +@interface MTRDeviceTypeRevision : NSObject /* (see below) */ - (instancetype)init NS_UNAVAILABLE; + (instancetype)new NS_UNAVAILABLE; @@ -38,9 +41,24 @@ MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) */ - (nullable instancetype)initWithDeviceTypeID:(NSNumber *)deviceTypeID revision:(NSNumber *)revision; +/** + * Initializes the receiver based on the values in the specified struct. + */ +- (nullable instancetype)initWithDeviceTypeStruct:(MTRDescriptorClusterDeviceTypeStruct *)deviceTypeStruct MTR_NEWLY_AVAILABLE; + @property (nonatomic, copy, readonly) NSNumber * deviceTypeID; @property (nonatomic, copy, readonly) NSNumber * deviceTypeRevision; +/** + * Returns the MTRDeviceType corresponding to deviceTypeID, + * or nil if deviceTypeID does not represent a known device type. + */ +@property (nonatomic, copy, readonly, nullable) MTRDeviceType * typeInformation MTR_NEWLY_AVAILABLE; + +@end + +MTR_NEWLY_AVAILABLE +@interface MTRDeviceTypeRevision () @end NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/ServerEndpoint/MTRDeviceTypeRevision.mm b/src/darwin/Framework/CHIP/MTRDeviceTypeRevision.mm similarity index 60% rename from src/darwin/Framework/CHIP/ServerEndpoint/MTRDeviceTypeRevision.mm rename to src/darwin/Framework/CHIP/MTRDeviceTypeRevision.mm index de5782c92e4aeb..2e71dcddbe411f 100644 --- a/src/darwin/Framework/CHIP/ServerEndpoint/MTRDeviceTypeRevision.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceTypeRevision.mm @@ -14,14 +14,19 @@ * limitations under the License. */ +#import "MTRDeviceTypeRevision.h" #import "MTRDefines_Internal.h" +#import "MTRDeviceType.h" #import "MTRLogging_Internal.h" -#import +#import "MTRStructsObjc.h" #include #include +#include #include +NS_ASSUME_NONNULL_BEGIN + using namespace chip; MTR_DIRECT_MEMBERS @@ -29,6 +34,9 @@ @implementation MTRDeviceTypeRevision - (nullable instancetype)initWithDeviceTypeID:(NSNumber *)deviceTypeID revision:(NSNumber *)revision { + VerifyOrReturnValue(deviceTypeID != nil, nil); + VerifyOrReturnValue(revision != nil, nil); + auto deviceTypeIDValue = deviceTypeID.unsignedLongLongValue; if (!CanCastTo(deviceTypeIDValue)) { MTR_LOG_ERROR("MTRDeviceTypeRevision provided too-large device type ID: 0x%llx", deviceTypeIDValue); @@ -50,20 +58,49 @@ - (nullable instancetype)initWithDeviceTypeID:(NSNumber *)deviceTypeID revision: return [self initInternalWithDeviceTypeID:[deviceTypeID copy] revision:[revision copy]]; } +- (nullable instancetype)initWithDeviceTypeStruct:(MTRDescriptorClusterDeviceTypeStruct *)deviceTypeStruct +{ + return [self initWithDeviceTypeID:deviceTypeStruct.deviceType revision:deviceTypeStruct.revision]; +} + // initInternalWithDeviceTypeID:revision assumes that the device type ID and device // revision have already been validated and, if needed, copied from the input. - (instancetype)initInternalWithDeviceTypeID:(NSNumber *)deviceTypeID revision:(NSNumber *)revision { - if (!(self = [super init])) { - return nil; - } - + self = [super init]; _deviceTypeID = deviceTypeID; _deviceTypeRevision = revision; return self; } -- (id)copyWithZone:(NSZone *)zone +static NSString * const sTypeIdCodingKey = @"ty"; +static NSString * const sRevisionCodingKey = @"re"; + +- (nullable instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super init]; + _deviceTypeID = @(static_cast([coder decodeInt64ForKey:sTypeIdCodingKey])); // int64_t encompasses uint32_t + _deviceTypeRevision = @(static_cast([coder decodeIntegerForKey:sRevisionCodingKey])); + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeInt64:static_cast(_deviceTypeID.unsignedLongLongValue) forKey:sTypeIdCodingKey]; + [coder encodeInteger:static_cast(_deviceTypeRevision.unsignedIntegerValue) forKey:sRevisionCodingKey]; +} + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (nullable MTRDeviceType *)typeInformation +{ + return [MTRDeviceType deviceTypeForID:_deviceTypeID]; +} + +- (id)copyWithZone:(nullable NSZone *)zone { // We have no mutable state. return self; @@ -85,4 +122,13 @@ - (NSUInteger)hash return _deviceTypeID.unsignedLongValue ^ _deviceTypeRevision.unsignedShortValue; } +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@ 0x%" PRIx32 " (%@) rev %d>", + self.class, _deviceTypeID.unsignedIntValue, + self.typeInformation.name ?: @"???", _deviceTypeRevision.unsignedIntValue]; +} + @end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTREndpointInfo.h b/src/darwin/Framework/CHIP/MTREndpointInfo.h new file mode 100644 index 00000000000000..dc271a05483442 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTREndpointInfo.h @@ -0,0 +1,48 @@ +/** + * 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. + */ + +#import + +@class MTRDeviceTypeRevision; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Meta-data about an endpoint of a Matter node. + */ +NS_SWIFT_SENDABLE +MTR_NEWLY_AVAILABLE +@interface MTREndpointInfo : NSObject + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@property (nonatomic, copy, readonly) NSNumber * endpointID; + +@property (nonatomic, copy, readonly) NSArray * deviceTypes; +@property (nonatomic, copy, readonly) NSArray * partsList; + +/** + * The direct children of this endpoint. This excludes indirect descendants + * even if they are listed in the PartsList attribute of this endpoint due + * to the Full-Family Pattern being used. Refer to Endpoint Composition Patterns + * in the Matter specification for details. + */ +@property (nonatomic, copy, readonly) NSArray * children; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTREndpointInfo.mm b/src/darwin/Framework/CHIP/MTREndpointInfo.mm new file mode 100644 index 00000000000000..b9a0fbf7fb4250 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTREndpointInfo.mm @@ -0,0 +1,269 @@ +/** + * 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. + */ + +#import "MTREndpointInfo_Internal.h" + +#import "MTRAttributeTLVValueDecoder_Internal.h" +#import "MTRDeviceTypeRevision.h" +#import "MTRLogging_Internal.h" +#import "MTRStructsObjc.h" + +#include +#include + +#include + +NS_ASSUME_NONNULL_BEGIN + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; + +enum class EndpointMark : uint8_t { + NotVisited = 0, + Visiting, + Visited, + ParentAssigned = NotVisited, // != Visited +}; + +MTR_DIRECT_MEMBERS +@implementation MTREndpointInfo { + EndpointId _endpointID; + EndpointMark _mark; // used by populateChildrenForEndpoints: +} + +- (instancetype)initWithEndpointID:(NSNumber *)endpointID + deviceTypes:(NSArray *)deviceTypes + partsList:(NSArray *)partsList +{ + self = [super init]; + _endpointID = endpointID.unsignedShortValue; + _deviceTypes = [deviceTypes copy]; + _partsList = [partsList copy]; + _children = @[]; + _mark = EndpointMark::NotVisited; + return self; +} + +static NSString * const sEndpointIDCodingKey = @"id"; +static NSString * const sDeviceTypesCodingKey = @"dt"; +static NSString * const sPartsListCodingKey = @"pl"; +static NSString * const sChildrenCodingKey = @"ch"; + +- (nullable instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super init]; + _endpointID = static_cast([coder decodeIntegerForKey:sEndpointIDCodingKey]); + _deviceTypes = [coder decodeArrayOfObjectsOfClass:MTRDeviceTypeRevision.class forKey:sDeviceTypesCodingKey]; + VerifyOrReturnValue(_deviceTypes != nil, nil); + _partsList = [coder decodeArrayOfObjectsOfClass:NSNumber.class forKey:sPartsListCodingKey]; + VerifyOrReturnValue(_partsList != nil, nil); + _children = [coder decodeArrayOfObjectsOfClass:MTREndpointInfo.class forKey:sChildrenCodingKey]; + VerifyOrReturnValue(_children != nil, nil); + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeInteger:_endpointID forKey:sEndpointIDCodingKey]; + [coder encodeObject:_deviceTypes forKey:sDeviceTypesCodingKey]; + [coder encodeObject:_partsList forKey:sPartsListCodingKey]; + [coder encodeObject:_children forKey:sChildrenCodingKey]; +} + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)copyWithZone:(nullable NSZone *)zone +{ + return self; // no (externally) mutable state +} + +- (NSUInteger)hash +{ + return _endpointID; +} + +- (BOOL)isEqual:(id)object +{ + VerifyOrReturnValue([object class] == [self class], NO); + MTREndpointInfo * other = object; + VerifyOrReturnValue(_endpointID == other->_endpointID, NO); + VerifyOrReturnValue([_deviceTypes isEqual:other->_deviceTypes], NO); + VerifyOrReturnValue([_partsList isEqual:other->_partsList], NO); + // Children are derived from PartsLists, so we don't need to compare them. + // This avoids a lot recursive comparisons when comparing a dictionary of endpoints. + return YES; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@ %u>", self.class, _endpointID]; +} + +- (NSNumber *)endpointID +{ + return @(_endpointID); +} + ++ (BOOL)populateChildrenForEndpoints:(NSDictionary *)endpoints +{ + // Populate the child list of each endpoint, ensuring no cycles (these are disallowed + // by the spec, but we need to ensure we don't create a retain cycle even under invalid + // input). Conservatively assume all endpoints use the Full-Family Pattern. + // Refer to "Endpoint Composition" in the Matter specification for details. + MTREndpointInfo * root = endpoints[@0]; + if (root == nil) { + MTR_LOG_ERROR("Missing root endpoint, not populating endpoint hierarchy"); + return NO; + } + + // Perform a depth-first search with an explicit stack and create a list of endpoint + // IDs in reverse topological order. Note that endpoints start with _mark == NotVisited. + BOOL valid = YES; + std::deque deque; // stack followed by sorted list + deque.emplace_front(root->_endpointID); + for (;;) { + EndpointId endpointID = deque.front(); + MTREndpointInfo * endpoint = endpoints[@(endpointID)]; + if (endpoint->_mark == EndpointMark::NotVisited) { + endpoint->_mark = EndpointMark::Visiting; + for (NSNumber * partNumber in endpoint->_partsList) { + MTREndpointInfo * descendant = endpoints[partNumber]; + if (!descendant) { + MTR_LOG_ERROR("Warning: PartsList of endpoint %u references non-existant endpoint %u", + endpointID, partNumber.unsignedShortValue); + valid = NO; + } else if (descendant->_mark == EndpointMark::NotVisited) { + deque.emplace_front(descendant->_endpointID); + } else if (descendant->_mark == EndpointMark::Visiting) { + MTR_LOG_ERROR("Warning: Cyclic endpoint composition involving endpoints %u and %u", + descendant->_endpointID, endpointID); + valid = NO; + } + } + } else if (endpoint->_mark == EndpointMark::Visiting) { + endpoint->_mark = EndpointMark::Visited; + deque.pop_front(); // remove from stack + deque.emplace_back(endpointID); // add to sorted list + if (endpointID == root->_endpointID) { + break; // visited the root, DFS traversal done + } + } else /* endpoint->_mark == EndpointMark::Visited */ { + // Endpoints can be visited multiple times due to Full-Family + // ancestors like the root node, or in scenarios where an + // endpoint is erroneously in the PartsList of two separate + // branches of the tree. There is no easy way to distinguish + // these cases here, so we are not setting valid = NO. + deque.pop_front(); // nothing else to do + } + } + if (deque.size() != endpoints.count) { + MTR_LOG_ERROR("Warning: Not all endpoints are descendants of the root endpoint"); + valid = NO; + } + + // Now iterate over the endpoints in reverse topological order, i.e. bottom up. This means + // that we will visit children before parents, so the first time we see an endpoint in a + // PartsList we can assign it as a child of the endpoint we're processing, and we can be sure + // that this is the closest parent, not some higher ancestor using the Full-Family Pattern. + NSMutableArray * children = [[NSMutableArray alloc] init]; + while (!deque.empty()) { + EndpointId endpointID = deque.front(); + MTREndpointInfo * endpoint = endpoints[@(endpointID)]; + deque.pop_front(); + + if (endpoint->_mark == EndpointMark::ParentAssigned) { + continue; // This endpoint is part of a cycle, don't populate its children. + } + + [children removeAllObjects]; + for (NSNumber * partNumber in endpoint->_partsList) { + MTREndpointInfo * descendant = endpoints[partNumber]; + if (descendant != nil && descendant->_mark != EndpointMark::ParentAssigned) { + descendant->_mark = EndpointMark::ParentAssigned; + [children addObject:descendant]; + } + } + endpoint->_children = [children copy]; + } + root->_mark = EndpointMark::ParentAssigned; + return valid; +} + ++ (NSDictionary *)endpointsFromAttributeCache:(const ClusterStateCache *)cache +{ + VerifyOrReturnValue(cache != nullptr, nil); + using namespace Descriptor::Attributes; + + NSMutableDictionary * endpoints = [[NSMutableDictionary alloc] init]; + cache->ForEachAttribute(Descriptor::Id, [&](const ConcreteAttributePath & path) -> CHIP_ERROR { + VerifyOrReturnError(path.mAttributeId == DeviceTypeList::Id, CHIP_NO_ERROR); + + CHIP_ERROR err = CHIP_NO_ERROR; + NSArray * deviceTypeList = MTRDecodeAttributeValue(path, *cache, &err); + if (!deviceTypeList) { + MTR_LOG_ERROR("Ignoring invalid DeviceTypeList for endpoint %u: %" CHIP_ERROR_FORMAT, path.mEndpointId, err.Format()); + // proceed with deviceTypeList == nil, equivalent to an empty list + } + + NSMutableArray * deviceTypes = [[NSMutableArray alloc] initWithCapacity:deviceTypeList.count]; + for (MTRDescriptorClusterDeviceTypeStruct * deviceTypeStruct in deviceTypeList) { + MTRDeviceTypeRevision * type = [[MTRDeviceTypeRevision alloc] initWithDeviceTypeStruct:deviceTypeStruct]; + if (!type) { + MTR_LOG_ERROR("Ignoring invalid device type 0x%x rev %u for endpoint %u", + deviceTypeStruct.deviceType.unsignedIntValue, deviceTypeStruct.revision.unsignedShortValue, + path.mEndpointId); + continue; + } + [deviceTypes addObject:type]; + } + + ConcreteAttributePath partsListPath(path.mEndpointId, path.mClusterId, PartsList::Id); + NSArray * partsList = MTRDecodeAttributeValue(partsListPath, *cache, &err); + if (!partsList) { + MTR_LOG_ERROR("Ignoring invalid PartsList for endpoint %u: %" CHIP_ERROR_FORMAT, path.mEndpointId, err.Format()); + partsList = @[]; + } + + MTREndpointInfo * endpoint = [[MTREndpointInfo alloc] initWithEndpointID:@(path.mEndpointId) + deviceTypes:deviceTypes + partsList:partsList]; + endpoints[endpoint.endpointID] = endpoint; + return CHIP_NO_ERROR; + }); + + if (endpoints.count > 0) { + [self populateChildrenForEndpoints:endpoints]; + } + return [endpoints copy]; +} + ++ (Span)requiredAttributePaths +{ + using namespace Descriptor::Attributes; + static constexpr AttributePathParams kPaths[] = { + AttributePathParams(Descriptor::Id, DeviceTypeList::Id), + AttributePathParams(Descriptor::Id, PartsList::Id), + }; + return Span(kPaths); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTREndpointInfo_Internal.h b/src/darwin/Framework/CHIP/MTREndpointInfo_Internal.h new file mode 100644 index 00000000000000..298ee8dab5241b --- /dev/null +++ b/src/darwin/Framework/CHIP/MTREndpointInfo_Internal.h @@ -0,0 +1,48 @@ +/** + * 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. + */ + +#import "MTREndpointInfo_Test.h" + +#include +#include +#include + +NS_ASSUME_NONNULL_BEGIN + +MTR_DIRECT_MEMBERS +@interface MTREndpointInfo () + +/** + * Returns a dictionary of endpoint metadata for a node. + * + * The provided cache must contain the result of reading the + * DeviceTypeList and PartsList attributes of all endpoints + * (as exposed by `requiredAttributePaths`). + * + * Any relevant information will be copied out of the cache; + * the caller is free to deallocate the cache once this method returns. + */ ++ (NSDictionary *)endpointsFromAttributeCache:(const chip::app::ClusterStateCache *)cache; + +/** + * Returns the set of AttributePathParams that must be read + * to populate endpoint information for a node. + */ ++ (chip::Span)requiredAttributePaths; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTREndpointInfo_Test.h b/src/darwin/Framework/CHIP/MTREndpointInfo_Test.h new file mode 100644 index 00000000000000..8e36e8f74aacb5 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTREndpointInfo_Test.h @@ -0,0 +1,38 @@ +/** + * 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. + */ + +#import + +#import "MTRDefines_Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +MTR_TESTABLE_DIRECT_MEMBERS +@interface MTREndpointInfo () + +- (instancetype)initWithEndpointID:(NSNumber *)endpointID + deviceTypes:(NSArray *)deviceTypes + partsList:(NSArray *)partsList; + +// Populates the children array for each endpoint in the provided dictionary. +// Returns YES if the endpoint hierarchy was populated correctly. +// A return value of NO indicates that there were some issues, but +// an effort has been made to populate a valid subset of the hierarchy. ++ (BOOL)populateChildrenForEndpoints:(NSDictionary *)endpoints; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h index 928c80ba85a0cb..86a054a550c504 100644 --- a/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h +++ b/src/darwin/Framework/CHIP/MTROperationalCredentialsDelegate.h @@ -1,6 +1,5 @@ /** - * - * Copyright (c) 2021-2023 Project CHIP Authors + * 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. @@ -15,8 +14,6 @@ * limitations under the License. */ -#include - #import #import @@ -32,6 +29,8 @@ #include #include +#include + NS_ASSUME_NONNULL_BEGIN class MTROperationalCredentialsDelegate : public chip::Controller::OperationalCredentialsDelegate { @@ -63,11 +62,6 @@ class MTROperationalCredentialsDelegate : public chip::Controller::OperationalCr mCppCommissioner = cppCommissioner; } - chip::Optional GetCommissioningParameters() - { - return mCppCommissioner == nullptr ? chip::NullOptional : mCppCommissioner->GetCommissioningParameters(); - } - void SetOperationalCertificateIssuer( id operationalCertificateIssuer, dispatch_queue_t operationalCertificateIssuerQueue) { diff --git a/src/darwin/Framework/CHIP/MTRProductIdentity.h b/src/darwin/Framework/CHIP/MTRProductIdentity.h new file mode 100644 index 00000000000000..7277c6441521c1 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRProductIdentity.h @@ -0,0 +1,42 @@ +/** + * 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. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * A representation of a (vendor, product) pair that identifies a specific product. + */ +NS_SWIFT_SENDABLE +MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) +@interface MTRProductIdentity : NSObject /* (see below) */ + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +- (instancetype)initWithVendorID:(NSNumber *)vendorID productID:(NSNumber *)productID; + +@property (nonatomic, copy, readonly) NSNumber * vendorID; +@property (nonatomic, copy, readonly) NSNumber * productID; + +@end + +MTR_NEWLY_AVAILABLE +@interface MTRProductIdentity () +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRProductIdentity.mm b/src/darwin/Framework/CHIP/MTRProductIdentity.mm new file mode 100644 index 00000000000000..c236d8a4489e81 --- /dev/null +++ b/src/darwin/Framework/CHIP/MTRProductIdentity.mm @@ -0,0 +1,95 @@ +/** + * 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. + */ + +#import "MTRProductIdentity.h" + +#import "MTRDefines_Internal.h" +#import "MTRUtilities.h" + +#include + +MTR_DIRECT_MEMBERS +@implementation MTRProductIdentity { + uint16_t _vendorID; + uint16_t _productID; +} + +- (instancetype)initWithVendorID:(NSNumber *)vendorID productID:(NSNumber *)productID +{ + self = [super init]; + VerifyOrReturnValue(vendorID != nil && productID != nil, nil); + _vendorID = vendorID.unsignedShortValue; + _productID = productID.unsignedShortValue; + return self; +} + +static NSString * const sVendorIDKey = @"v"; +static NSString * const sProductIDKey = @"p"; + +- (nullable instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super init]; + _vendorID = static_cast([coder decodeIntForKey:sVendorIDKey]); + _productID = static_cast([coder decodeIntForKey:sProductIDKey]); + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeInt:_vendorID forKey:sVendorIDKey]; + [coder encodeInt:_productID forKey:sProductIDKey]; +} + ++ (BOOL)supportsSecureCoding +{ + return YES; +} + +- (id)copyWithZone:(NSZone *)zone +{ + return self; // immutable +} + +- (NSUInteger)hash +{ + return (_vendorID << 16) | _productID; +} + +- (BOOL)isEqual:(id)object +{ + VerifyOrReturnValue([object class] == [self class], NO); + MTRProductIdentity * other = object; + VerifyOrReturnValue(_vendorID == other->_vendorID, NO); + VerifyOrReturnValue(_productID == other->_productID, NO); + return YES; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@: vid 0x%x pid 0x%x>", self.class, _vendorID, _productID]; +} + +- (NSNumber *)vendorID +{ + return @(_vendorID); +} + +- (NSNumber *)productID +{ + return @(_productID); +} + +@end diff --git a/src/darwin/Framework/CHIP/Matter.h b/src/darwin/Framework/CHIP/Matter.h index 85a87c4ba12c0c..bf643f654bf763 100644 --- a/src/darwin/Framework/CHIP/Matter.h +++ b/src/darwin/Framework/CHIP/Matter.h @@ -36,6 +36,7 @@ #import #import #import +#import #import #import #import @@ -52,6 +53,7 @@ #import #import #import +#import #import #import #import @@ -62,6 +64,7 @@ #import #import #import +#import #import #import #import diff --git a/src/darwin/Framework/CHIP/templates/MTRDeviceTypeMetadata-src.zapt b/src/darwin/Framework/CHIP/templates/MTRDeviceTypeMetadata-src.zapt index 16322f398e9694..df3e1ab99f00ac 100644 --- a/src/darwin/Framework/CHIP/templates/MTRDeviceTypeMetadata-src.zapt +++ b/src/darwin/Framework/CHIP/templates/MTRDeviceTypeMetadata-src.zapt @@ -6,10 +6,12 @@ using namespace chip; namespace { -constexpr MTRDeviceTypeData knownDeviceTypes[] = { +// Not constexpr in the strict sense because NSString * is not a literal +// type, but the array is in fact constant initialized by the compiler. +static /* constexpr */ const MTRDeviceTypeData knownDeviceTypes[] = { {{#zcl_device_types}} {{#if class}} - { {{asHex code 8}}, MTRDeviceTypeClass::{{class}}, "{{caption}}" }, + { {{asHex code 8}}, MTRDeviceTypeClass::{{class}}, @"{{caption}}" }, {{/if}} {{/zcl_device_types}} }; diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm b/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm index cec53390010b33..9e4b98f3ffdb77 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRDeviceTypeMetadata.mm @@ -21,77 +21,79 @@ namespace { -constexpr MTRDeviceTypeData knownDeviceTypes[] = { - { 0x0000000A, MTRDeviceTypeClass::Simple, "Door Lock" }, - { 0x0000000B, MTRDeviceTypeClass::Simple, "Door Lock Controller" }, - { 0x0000000E, MTRDeviceTypeClass::Simple, "Aggregator" }, - { 0x0000000F, MTRDeviceTypeClass::Simple, "Generic Switch" }, - { 0x00000011, MTRDeviceTypeClass::Utility, "Power Source" }, - { 0x00000012, MTRDeviceTypeClass::Utility, "OTA Requestor" }, - { 0x00000013, MTRDeviceTypeClass::Utility, "Bridged Node" }, - { 0x00000014, MTRDeviceTypeClass::Utility, "OTA Provider" }, - { 0x00000015, MTRDeviceTypeClass::Simple, "Contact Sensor" }, - { 0x00000016, MTRDeviceTypeClass::Node, "Root Node" }, - { 0x00000017, MTRDeviceTypeClass::Simple, "Solar Power" }, - { 0x00000018, MTRDeviceTypeClass::Simple, "Battery Storage" }, - { 0x00000019, MTRDeviceTypeClass::Utility, "Secondary Network Interface" }, - { 0x00000022, MTRDeviceTypeClass::Simple, "Speaker" }, - { 0x00000023, MTRDeviceTypeClass::Simple, "Casting Video Player" }, - { 0x00000024, MTRDeviceTypeClass::Simple, "Content App" }, - { 0x00000027, MTRDeviceTypeClass::Simple, "Mode Select" }, - { 0x00000028, MTRDeviceTypeClass::Simple, "Basic Video Player" }, - { 0x00000029, MTRDeviceTypeClass::Simple, "Casting Video Client" }, - { 0x0000002A, MTRDeviceTypeClass::Simple, "Video Remote Control" }, - { 0x0000002B, MTRDeviceTypeClass::Simple, "Fan" }, - { 0x0000002C, MTRDeviceTypeClass::Simple, "Air Quality Sensor" }, - { 0x0000002D, MTRDeviceTypeClass::Simple, "Air Purifier" }, - { 0x00000041, MTRDeviceTypeClass::Simple, "Water Freeze Detector" }, - { 0x00000042, MTRDeviceTypeClass::Simple, "Water Valve" }, - { 0x00000043, MTRDeviceTypeClass::Simple, "Water Leak Detector" }, - { 0x00000044, MTRDeviceTypeClass::Simple, "Rain Sensor" }, - { 0x00000070, MTRDeviceTypeClass::Simple, "Refrigerator" }, - { 0x00000071, MTRDeviceTypeClass::Simple, "Temperature Controlled Cabinet" }, - { 0x00000072, MTRDeviceTypeClass::Simple, "Room Air Conditioner" }, - { 0x00000073, MTRDeviceTypeClass::Simple, "Laundry Washer" }, - { 0x00000074, MTRDeviceTypeClass::Simple, "Robotic Vacuum Cleaner" }, - { 0x00000075, MTRDeviceTypeClass::Simple, "Dishwasher" }, - { 0x00000076, MTRDeviceTypeClass::Simple, "Smoke CO Alarm" }, - { 0x00000077, MTRDeviceTypeClass::Simple, "Cook Surface" }, - { 0x00000078, MTRDeviceTypeClass::Simple, "Cooktop" }, - { 0x00000079, MTRDeviceTypeClass::Simple, "Microwave Oven" }, - { 0x0000007A, MTRDeviceTypeClass::Simple, "Extractor Hood" }, - { 0x0000007B, MTRDeviceTypeClass::Simple, "Oven" }, - { 0x0000007C, MTRDeviceTypeClass::Simple, "Laundry Dryer" }, - { 0x00000090, MTRDeviceTypeClass::Simple, "Network Infrastructure Manager" }, - { 0x00000091, MTRDeviceTypeClass::Simple, "Thread Border Router" }, - { 0x00000100, MTRDeviceTypeClass::Simple, "On/Off Light" }, - { 0x00000101, MTRDeviceTypeClass::Simple, "Dimmable Light" }, - { 0x00000103, MTRDeviceTypeClass::Simple, "On/Off Light Switch" }, - { 0x00000104, MTRDeviceTypeClass::Simple, "Dimmer Switch" }, - { 0x00000105, MTRDeviceTypeClass::Simple, "Color Dimmer Switch" }, - { 0x00000106, MTRDeviceTypeClass::Simple, "Light Sensor" }, - { 0x00000107, MTRDeviceTypeClass::Simple, "Occupancy Sensor" }, - { 0x0000010A, MTRDeviceTypeClass::Simple, "On/Off Plug-in Unit" }, - { 0x0000010B, MTRDeviceTypeClass::Simple, "Dimmable Plug-in Unit" }, - { 0x0000010C, MTRDeviceTypeClass::Simple, "Color Temperature Light" }, - { 0x0000010D, MTRDeviceTypeClass::Simple, "Extended Color Light" }, - { 0x00000202, MTRDeviceTypeClass::Simple, "Window Covering" }, - { 0x00000203, MTRDeviceTypeClass::Simple, "Window Covering Controller" }, - { 0x00000300, MTRDeviceTypeClass::Simple, "Heating/Cooling Unit" }, - { 0x00000301, MTRDeviceTypeClass::Simple, "Thermostat" }, - { 0x00000302, MTRDeviceTypeClass::Simple, "Temperature Sensor" }, - { 0x00000303, MTRDeviceTypeClass::Simple, "Pump" }, - { 0x00000304, MTRDeviceTypeClass::Simple, "Pump Controller" }, - { 0x00000305, MTRDeviceTypeClass::Simple, "Pressure Sensor" }, - { 0x00000306, MTRDeviceTypeClass::Simple, "Flow Sensor" }, - { 0x00000307, MTRDeviceTypeClass::Simple, "Humidity Sensor" }, - { 0x00000309, MTRDeviceTypeClass::Simple, "Heat Pump" }, - { 0x0000050C, MTRDeviceTypeClass::Simple, "EVSE" }, - { 0x0000050D, MTRDeviceTypeClass::Utility, "Device Energy Management" }, - { 0x0000050F, MTRDeviceTypeClass::Simple, "Water Heater" }, - { 0x00000510, MTRDeviceTypeClass::Utility, "Electrical Sensor" }, - { 0x00000840, MTRDeviceTypeClass::Simple, "Control Bridge" }, - { 0x00000850, MTRDeviceTypeClass::Simple, "On/Off Sensor" }, +// Not constexpr in the strict sense because NSString * is not a literal +// type, but the array is in fact constant initialized by the compiler. +static /* constexpr */ const MTRDeviceTypeData knownDeviceTypes[] = { + { 0x0000000A, MTRDeviceTypeClass::Simple, @"Door Lock" }, + { 0x0000000B, MTRDeviceTypeClass::Simple, @"Door Lock Controller" }, + { 0x0000000E, MTRDeviceTypeClass::Simple, @"Aggregator" }, + { 0x0000000F, MTRDeviceTypeClass::Simple, @"Generic Switch" }, + { 0x00000011, MTRDeviceTypeClass::Utility, @"Power Source" }, + { 0x00000012, MTRDeviceTypeClass::Utility, @"OTA Requestor" }, + { 0x00000013, MTRDeviceTypeClass::Utility, @"Bridged Node" }, + { 0x00000014, MTRDeviceTypeClass::Utility, @"OTA Provider" }, + { 0x00000015, MTRDeviceTypeClass::Simple, @"Contact Sensor" }, + { 0x00000016, MTRDeviceTypeClass::Node, @"Root Node" }, + { 0x00000017, MTRDeviceTypeClass::Simple, @"Solar Power" }, + { 0x00000018, MTRDeviceTypeClass::Simple, @"Battery Storage" }, + { 0x00000019, MTRDeviceTypeClass::Utility, @"Secondary Network Interface" }, + { 0x00000022, MTRDeviceTypeClass::Simple, @"Speaker" }, + { 0x00000023, MTRDeviceTypeClass::Simple, @"Casting Video Player" }, + { 0x00000024, MTRDeviceTypeClass::Simple, @"Content App" }, + { 0x00000027, MTRDeviceTypeClass::Simple, @"Mode Select" }, + { 0x00000028, MTRDeviceTypeClass::Simple, @"Basic Video Player" }, + { 0x00000029, MTRDeviceTypeClass::Simple, @"Casting Video Client" }, + { 0x0000002A, MTRDeviceTypeClass::Simple, @"Video Remote Control" }, + { 0x0000002B, MTRDeviceTypeClass::Simple, @"Fan" }, + { 0x0000002C, MTRDeviceTypeClass::Simple, @"Air Quality Sensor" }, + { 0x0000002D, MTRDeviceTypeClass::Simple, @"Air Purifier" }, + { 0x00000041, MTRDeviceTypeClass::Simple, @"Water Freeze Detector" }, + { 0x00000042, MTRDeviceTypeClass::Simple, @"Water Valve" }, + { 0x00000043, MTRDeviceTypeClass::Simple, @"Water Leak Detector" }, + { 0x00000044, MTRDeviceTypeClass::Simple, @"Rain Sensor" }, + { 0x00000070, MTRDeviceTypeClass::Simple, @"Refrigerator" }, + { 0x00000071, MTRDeviceTypeClass::Simple, @"Temperature Controlled Cabinet" }, + { 0x00000072, MTRDeviceTypeClass::Simple, @"Room Air Conditioner" }, + { 0x00000073, MTRDeviceTypeClass::Simple, @"Laundry Washer" }, + { 0x00000074, MTRDeviceTypeClass::Simple, @"Robotic Vacuum Cleaner" }, + { 0x00000075, MTRDeviceTypeClass::Simple, @"Dishwasher" }, + { 0x00000076, MTRDeviceTypeClass::Simple, @"Smoke CO Alarm" }, + { 0x00000077, MTRDeviceTypeClass::Simple, @"Cook Surface" }, + { 0x00000078, MTRDeviceTypeClass::Simple, @"Cooktop" }, + { 0x00000079, MTRDeviceTypeClass::Simple, @"Microwave Oven" }, + { 0x0000007A, MTRDeviceTypeClass::Simple, @"Extractor Hood" }, + { 0x0000007B, MTRDeviceTypeClass::Simple, @"Oven" }, + { 0x0000007C, MTRDeviceTypeClass::Simple, @"Laundry Dryer" }, + { 0x00000090, MTRDeviceTypeClass::Simple, @"Network Infrastructure Manager" }, + { 0x00000091, MTRDeviceTypeClass::Simple, @"Thread Border Router" }, + { 0x00000100, MTRDeviceTypeClass::Simple, @"On/Off Light" }, + { 0x00000101, MTRDeviceTypeClass::Simple, @"Dimmable Light" }, + { 0x00000103, MTRDeviceTypeClass::Simple, @"On/Off Light Switch" }, + { 0x00000104, MTRDeviceTypeClass::Simple, @"Dimmer Switch" }, + { 0x00000105, MTRDeviceTypeClass::Simple, @"Color Dimmer Switch" }, + { 0x00000106, MTRDeviceTypeClass::Simple, @"Light Sensor" }, + { 0x00000107, MTRDeviceTypeClass::Simple, @"Occupancy Sensor" }, + { 0x0000010A, MTRDeviceTypeClass::Simple, @"On/Off Plug-in Unit" }, + { 0x0000010B, MTRDeviceTypeClass::Simple, @"Dimmable Plug-in Unit" }, + { 0x0000010C, MTRDeviceTypeClass::Simple, @"Color Temperature Light" }, + { 0x0000010D, MTRDeviceTypeClass::Simple, @"Extended Color Light" }, + { 0x00000202, MTRDeviceTypeClass::Simple, @"Window Covering" }, + { 0x00000203, MTRDeviceTypeClass::Simple, @"Window Covering Controller" }, + { 0x00000300, MTRDeviceTypeClass::Simple, @"Heating/Cooling Unit" }, + { 0x00000301, MTRDeviceTypeClass::Simple, @"Thermostat" }, + { 0x00000302, MTRDeviceTypeClass::Simple, @"Temperature Sensor" }, + { 0x00000303, MTRDeviceTypeClass::Simple, @"Pump" }, + { 0x00000304, MTRDeviceTypeClass::Simple, @"Pump Controller" }, + { 0x00000305, MTRDeviceTypeClass::Simple, @"Pressure Sensor" }, + { 0x00000306, MTRDeviceTypeClass::Simple, @"Flow Sensor" }, + { 0x00000307, MTRDeviceTypeClass::Simple, @"Humidity Sensor" }, + { 0x00000309, MTRDeviceTypeClass::Simple, @"Heat Pump" }, + { 0x0000050C, MTRDeviceTypeClass::Simple, @"EVSE" }, + { 0x0000050D, MTRDeviceTypeClass::Utility, @"Device Energy Management" }, + { 0x0000050F, MTRDeviceTypeClass::Simple, @"Water Heater" }, + { 0x00000510, MTRDeviceTypeClass::Utility, @"Electrical Sensor" }, + { 0x00000840, MTRDeviceTypeClass::Simple, @"Control Bridge" }, + { 0x00000850, MTRDeviceTypeClass::Simple, @"On/Off Sensor" }, }; static_assert(ExtractVendorFromMEI(0xFFF10001) != 0, "Must have class defined for \"Orphan Clusters\" if it's a standard device type"); diff --git a/src/darwin/Framework/CHIPTests/MTRDeviceTypeRevisionTests.m b/src/darwin/Framework/CHIPTests/MTRDeviceTypeRevisionTests.m new file mode 100644 index 00000000000000..f228e724df52a7 --- /dev/null +++ b/src/darwin/Framework/CHIPTests/MTRDeviceTypeRevisionTests.m @@ -0,0 +1,96 @@ +/** + * 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. + */ + +#import +#import + +@interface MTRDeviceTypeRevisionTests : XCTestCase +@end + +@implementation MTRDeviceTypeRevisionTests + +- (void)testInvalidTypeID +{ + XCTAssertNil([[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:(id _Nonnull) nil revision:@1]); + XCTAssertNil([[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@0xC000 revision:@1]); // type > 0xBFFF + XCTAssertNil([[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@0x100000000 revision:@1]); +} + +- (void)testInvalidRevision +{ + XCTAssertNil([[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@1 revision:(id _Nonnull) nil]); + XCTAssertNil([[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@1 revision:@0]); // < 1 + XCTAssertNil([[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@1 revision:@0x10000]); // > 0xFFFF +} + +- (void)testInitWithStruct +{ + MTRDescriptorClusterDeviceTypeStruct * strukt = [[MTRDescriptorClusterDeviceTypeStruct alloc] init]; + strukt.deviceType = @42; + strukt.revision = @2; + MTRDeviceTypeRevision * typeRev = [[MTRDeviceTypeRevision alloc] initWithDeviceTypeStruct:strukt]; + XCTAssertNotNil(typeRev); + XCTAssertEqualObjects(typeRev, [[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@42 revision:@2]); +} + +- (void)testTypeInformation +{ + __auto_type * typeRev = [[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@(MTRDeviceTypeIDTypeRootNodeID) revision:@1]; + XCTAssertNotNil(typeRev); + XCTAssertNotNil(typeRev.typeInformation); + XCTAssertEqualObjects(typeRev.typeInformation.name, @"Root Node"); +} + +- (void)testEqualityAndCopying +{ + __auto_type * a1 = [[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@(MTRDeviceTypeIDTypeMicrowaveOvenID) revision:@1]; + XCTAssertNotNil(a1); + XCTAssertTrue([a1 isEqual:a1]); + XCTAssertTrue([a1 isEqual:[a1 copy]]); + XCTAssertFalse([a1 isEqual:nil]); + XCTAssertFalse([a1 isEqual:@(MTRDeviceTypeIDTypeMicrowaveOvenID)]); + + __auto_type * a2 = [[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@(MTRDeviceTypeIDTypeMicrowaveOvenID) revision:@1]; + XCTAssertNotNil(a2); + XCTAssertEqual(a1.hash, a2.hash); + XCTAssertTrue([a1 isEqual:a2]); + XCTAssertTrue([a2 isEqual:a1]); + + __auto_type * b = [[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@(MTRDeviceTypeIDTypePowerSourceID) revision:@1]; + XCTAssertNotNil(b); + XCTAssertFalse([a1 isEqual:b]); + XCTAssertFalse([b isEqual:a1]); + + __auto_type * c = [[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@(MTRDeviceTypeIDTypeMicrowaveOvenID) revision:@2]; + XCTAssertNotNil(c); + XCTAssertFalse([c isEqual:a1]); + XCTAssertFalse([a1 isEqual:c]); + XCTAssertFalse([c isEqual:b]); + XCTAssertFalse([b isEqual:c]); +} + +- (void)testSecureCoding +{ + MTRDeviceTypeRevision * a = [[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@(MTRDeviceTypeIDTypeMicrowaveOvenID) revision:@1]; + NSData * data = [NSKeyedArchiver archivedDataWithRootObject:a requiringSecureCoding:YES error:NULL]; + MTRDeviceTypeRevision * b = [NSKeyedUnarchiver unarchivedObjectOfClass:MTRDeviceTypeRevision.class fromData:data error:NULL]; + XCTAssertNotNil(b); + XCTAssertEqualObjects(b.deviceTypeID, a.deviceTypeID); + XCTAssertEqualObjects(b.deviceTypeRevision, a.deviceTypeRevision); + XCTAssertTrue([b isEqual:a]); +} + +@end diff --git a/src/darwin/Framework/CHIPTests/MTRDeviceTypeTests.m b/src/darwin/Framework/CHIPTests/MTRDeviceTypeTests.m index 7a41d42b40cb43..1a3f3fc740c722 100644 --- a/src/darwin/Framework/CHIPTests/MTRDeviceTypeTests.m +++ b/src/darwin/Framework/CHIPTests/MTRDeviceTypeTests.m @@ -15,12 +15,9 @@ */ #import - -// system dependencies #import @interface MTRDeviceTypeTests : XCTestCase - @end @implementation MTRDeviceTypeTests @@ -55,7 +52,7 @@ - (void)testKnownUtilityID XCTAssertTrue(deviceType.isUtility); } -- (void)testRootNodeID +- (void)testPowerSource { __auto_type * deviceType = [MTRDeviceType deviceTypeForID:@(MTRDeviceTypeIDTypePowerSourceID)]; XCTAssertNotNil(deviceType); @@ -64,4 +61,24 @@ - (void)testRootNodeID XCTAssertTrue(deviceType.isUtility); } +- (void)testEqualityAndCopying +{ + __auto_type * a1 = [MTRDeviceType deviceTypeForID:@(MTRDeviceTypeIDTypeMicrowaveOvenID)]; + XCTAssertNotNil(a1); + XCTAssertTrue([a1 isEqual:a1]); + XCTAssertFalse([a1 isEqual:nil]); + XCTAssertFalse([a1 isEqual:@(MTRDeviceTypeIDTypeMicrowaveOvenID)]); + + __auto_type * a2 = [MTRDeviceType deviceTypeForID:@(MTRDeviceTypeIDTypeMicrowaveOvenID)]; + XCTAssertNotNil(a2); + XCTAssertEqual(a1.hash, a2.hash); + XCTAssertTrue([a1 isEqual:a2]); + XCTAssertTrue([a2 isEqual:a1]); + + __auto_type * b = [MTRDeviceType deviceTypeForID:@(MTRDeviceTypeIDTypePowerSourceID)]; + XCTAssertNotNil(b); + XCTAssertFalse([a1 isEqual:b]); + XCTAssertFalse([b isEqual:a1]); +} + @end diff --git a/src/darwin/Framework/CHIPTests/MTREndpointInfoTests.m b/src/darwin/Framework/CHIPTests/MTREndpointInfoTests.m new file mode 100644 index 00000000000000..1999eb478b5711 --- /dev/null +++ b/src/darwin/Framework/CHIPTests/MTREndpointInfoTests.m @@ -0,0 +1,201 @@ +/** + * 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. + */ + +#import "MTREndpointInfo_Test.h" +#import + +#import + +@interface MTREndpointInfoTests : XCTestCase +@end + +@implementation MTREndpointInfoTests + +static MTREndpointInfo * MakeEndpoint(NSNumber * endpointID, NSArray * parts) +{ + return [[MTREndpointInfo alloc] initWithEndpointID:endpointID deviceTypes:@[] partsList:parts]; +} + +static NSArray * ChildEndpointIDs(MTREndpointInfo * endpoint) +{ + return [[endpoint.children valueForKey:@"endpointID"] sortedArrayUsingSelector:@selector(compare:)]; +} + +static NSArray * Exclude(NSArray * numbers, NSNumber * numberToExclude) +{ + NSMutableArray * result = [numbers mutableCopy]; + [result removeObject:numberToExclude]; + return result; +} + +- (NSDictionary *)indexEndpoints:(NSArray *)endpoints +{ + NSMutableDictionary * indexed = [[NSMutableDictionary alloc] init]; + for (MTREndpointInfo * endpoint in endpoints) { + indexed[endpoint.endpointID] = endpoint; + } + XCTAssertEqual(indexed.count, endpoints.count, @"Duplicate endpoint IDs"); + return indexed; +} + +- (void)testPopulateChildren +{ + NSDictionary * endpoints = [self indexEndpoints:@[ + MakeEndpoint(@0, @[ @1, @2, @3, @4, @5, @6 ]), // full-family pattern + MakeEndpoint(@1, @[ @2, @3 ]), + MakeEndpoint(@2, @[]), + MakeEndpoint(@3, @[]), + MakeEndpoint(@4, @[ @5, @6 ]), // full-family pattern + MakeEndpoint(@5, @[ @6 ]), + MakeEndpoint(@6, @[]), + ]]; + XCTAssertTrue([MTREndpointInfo populateChildrenForEndpoints:endpoints]); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@0]), (@[ @1, @4 ])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@1]), (@[ @2, @3 ])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@2]), (@[])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@3]), (@[])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@4]), (@[ @5 ])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@5]), (@[ @6 ])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@6]), (@[])); +} + +- (void)testPopulateChildren2 +{ + // Same as testPopulateChildren, but with reversed PartsLists + NSDictionary * endpoints = [self indexEndpoints:@[ + MakeEndpoint(@0, @[ @6, @5, @4, @3, @2, @1 ]), // full-family pattern + MakeEndpoint(@1, @[ @3, @2 ]), + MakeEndpoint(@2, @[]), + MakeEndpoint(@3, @[]), + MakeEndpoint(@4, @[ @6, @5 ]), // full-family pattern + MakeEndpoint(@5, @[ @6 ]), + MakeEndpoint(@6, @[]), + ]]; + XCTAssertTrue([MTREndpointInfo populateChildrenForEndpoints:endpoints]); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@0]), (@[ @1, @4 ])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@1]), (@[ @2, @3 ])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@2]), (@[])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@3]), (@[])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@4]), (@[ @5 ])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@5]), (@[ @6 ])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@6]), (@[])); +} + +- (void)testPopulateChildrenRootOnly +{ + NSDictionary * endpoints = [self indexEndpoints:@[ + MakeEndpoint(@0, @[]), + ]]; + XCTAssertTrue([MTREndpointInfo populateChildrenForEndpoints:endpoints]); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@0]), (@[])); +} + +- (void)testPopulateChildrenInvalidCompositionCycle +{ + NSDictionary * endpoints = [self indexEndpoints:@[ + MakeEndpoint(@0, @[ @1, @2, @3, @4, @5, @6 ]), // full-family pattern + MakeEndpoint(@1, @[ @2, @3 ]), + MakeEndpoint(@2, @[]), + MakeEndpoint(@3, @[]), + MakeEndpoint(@4, @[ @5, @6 ]), // full-family pattern + MakeEndpoint(@5, @[ @6 ]), + MakeEndpoint(@6, @[ @4 ]), // not valid per spec: cycle 4 -> 5 -> 6 -> 4 + ]]; + XCTAssertFalse([MTREndpointInfo populateChildrenForEndpoints:endpoints]); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@0]), (@[ @1, @4 ])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@1]), (@[ @2, @3 ])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@2]), (@[])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@3]), (@[])); + // We make no promises about child lists for endpoints involved in a cycle +} + +- (void)testPopulateChildrenInvalidNonTree +{ + NSDictionary * endpoints = [self indexEndpoints:@[ + MakeEndpoint(@0, @[ @1, @2, @3, @4, @5, @6 ]), // full-family pattern + MakeEndpoint(@1, @[ @2, @3, @6 ]), + MakeEndpoint(@2, @[]), + MakeEndpoint(@3, @[]), + MakeEndpoint(@4, @[ @5, @6 ]), // full-family pattern + MakeEndpoint(@5, @[ @6 ]), + MakeEndpoint(@6, @[]), // not valid per spec: 6 is a child of both 1 and 5 + ]]; + // Note: Not asserting a false return value here, this scenario is currently not detected. + [MTREndpointInfo populateChildrenForEndpoints:endpoints]; + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@0]), (@[ @1, @4 ])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@2]), (@[])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@3]), (@[])); + XCTAssertEqualObjects(ChildEndpointIDs(endpoints[@4]), (@[ @5 ])); + // Endpoint 6 has multiple parents, so we make no guarantees where (or if) it shows up + XCTAssertEqualObjects(Exclude(ChildEndpointIDs(endpoints[@1]), @6), (@[ @2, @3 ])); + XCTAssertEqualObjects(Exclude(ChildEndpointIDs(endpoints[@5]), @6), (@[])); +} + +- (void)testEqualityAndCopying +{ + MTRDeviceTypeRevision * doorLock = [[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@0x0A revision:@1]; + MTRDeviceTypeRevision * rootNode = [[MTRDeviceTypeRevision alloc] initWithDeviceTypeID:@0x16 revision:@1]; + MTREndpointInfo * a1 = [[MTREndpointInfo alloc] initWithEndpointID:@1 deviceTypes:@[ rootNode ] partsList:@[]]; + XCTAssertTrue([a1 isEqual:a1]); + XCTAssertTrue([a1 isEqual:[a1 copy]]); + XCTAssertFalse([a1 isEqual:nil]); + XCTAssertFalse([a1 isEqual:@"hello"]); + MTREndpointInfo * a2 = [[MTREndpointInfo alloc] initWithEndpointID:@1 deviceTypes:@[ rootNode ] partsList:@[]]; + XCTAssertTrue([a1 isEqual:a2]); + XCTAssertTrue([a2 isEqual:a1]); + XCTAssertEqual(a1.hash, a2.hash); + MTREndpointInfo * b = [[MTREndpointInfo alloc] initWithEndpointID:@1 deviceTypes:@[ rootNode ] partsList:@[ @2 ]]; + XCTAssertFalse([a1 isEqual:b]); + XCTAssertFalse([b isEqual:a1]); + MTREndpointInfo * c = [[MTREndpointInfo alloc] initWithEndpointID:@1 deviceTypes:@[ doorLock ] partsList:@[]]; + XCTAssertFalse([a1 isEqual:c]); + XCTAssertFalse([c isEqual:a1]); + MTREndpointInfo * d = [[MTREndpointInfo alloc] initWithEndpointID:@2 deviceTypes:@[ rootNode ] partsList:@[]]; + XCTAssertFalse([a1 isEqual:d]); + XCTAssertFalse([d isEqual:a1]); +} + +- (void)testSecureCoding +{ + NSDictionary * endpoints = [self indexEndpoints:@[ + MakeEndpoint(@0, @[ @1, @2, @3, @4, @5, @6 ]), // full-family pattern + MakeEndpoint(@1, @[ @2, @3 ]), + MakeEndpoint(@2, @[]), + MakeEndpoint(@3, @[]), + MakeEndpoint(@4, @[ @5, @6 ]), // full-family pattern + MakeEndpoint(@5, @[ @6 ]), + MakeEndpoint(@6, @[]), + ]]; + XCTAssertTrue([MTREndpointInfo populateChildrenForEndpoints:endpoints]); + + NSData * data = [NSKeyedArchiver archivedDataWithRootObject:endpoints.allValues requiringSecureCoding:YES error:NULL]; + NSArray * decodedEndpoints = [NSKeyedUnarchiver unarchivedArrayOfObjectsOfClass:MTREndpointInfo.class fromData:data error:NULL]; + + XCTAssertNotNil(decodedEndpoints); + XCTAssertEqualObjects(decodedEndpoints, endpoints.allValues); + + // Deeply compare by hand as well, `children` is not checked by isEqual: + [decodedEndpoints enumerateObjectsUsingBlock:^(MTREndpointInfo * decoded, NSUInteger idx, BOOL * stop) { + MTREndpointInfo * original = endpoints.allValues[idx]; + XCTAssertTrue([decoded isEqual:original]); + XCTAssertEqualObjects(decoded.endpointID, original.endpointID); + XCTAssertEqualObjects(decoded.deviceTypes, original.deviceTypes); + XCTAssertEqualObjects(decoded.partsList, original.partsList); + XCTAssertEqualObjects(decoded.children, original.children); + }]; +} + +@end diff --git a/src/darwin/Framework/CHIPTests/MTRPairingTests.m b/src/darwin/Framework/CHIPTests/MTRPairingTests.m index 675c04156e62ae..e0bac5f2a74ac7 100644 --- a/src/darwin/Framework/CHIPTests/MTRPairingTests.m +++ b/src/darwin/Framework/CHIPTests/MTRPairingTests.m @@ -1,6 +1,5 @@ -/* - * - * Copyright (c) 2022 Project CHIP Authors +/** + * Copyright (c) 2022-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. @@ -107,6 +106,7 @@ @interface MTRPairingTestControllerDelegate : NSObject attestationDelegate; @property (nonatomic, nullable) NSNumber * failSafeExtension; +@property (nonatomic) BOOL shouldReadEndpointInformation; @property (nullable) NSError * commissioningCompleteError; @end @@ -131,6 +131,7 @@ - (void)controller:(MTRDeviceController *)controller commissioningSessionEstabli __auto_type * params = [[MTRCommissioningParameters alloc] init]; params.deviceAttestationDelegate = self.attestationDelegate; params.failSafeTimeout = self.failSafeExtension; + params.readEndpointInformation = self.shouldReadEndpointInformation; NSError * commissionError = nil; XCTAssertTrue([controller commissionNodeWithID:@(sDeviceId) commissioningParams:params error:&commissionError], @@ -139,6 +140,40 @@ - (void)controller:(MTRDeviceController *)controller commissioningSessionEstabli // Keep waiting for onCommissioningComplete } +- (void)controller:(MTRDeviceController *)controller readCommissioneeInfo:(MTRCommissioneeInfo *)info +{ + XCTAssertNotNil(info.productIdentity); + XCTAssertEqualObjects(info.productIdentity.vendorID, /* Test Vendor 1 */ @0xFFF1); + + if (self.shouldReadEndpointInformation) { + XCTAssertNotNil(info.endpointsById); + XCTAssertNotNil(info.rootEndpoint); + XCTAssertGreaterThanOrEqual(info.rootEndpoint.children.count, 1); // at least one application endpoint + for (MTREndpointInfo * endpoint in info.endpointsById.allValues) { + XCTAssertGreaterThanOrEqual(endpoint.deviceTypes.count, 1); + XCTAssertNotNil(endpoint.children); + XCTAssertNotNil(endpoint.partsList); + XCTAssertGreaterThanOrEqual(endpoint.partsList.count, endpoint.children.count); + for (MTREndpointInfo * child in endpoint.children) { + XCTAssertTrue([endpoint.partsList containsObject:child.endpointID]); + } + } + + // There is currently no convenient way to initialize an MTRCommissioneeInfo + // object from basic ObjC data types, so we do some unit testing here. + NSData * data = [NSKeyedArchiver archivedDataWithRootObject:info requiringSecureCoding:YES error:NULL]; + MTRCommissioneeInfo * decoded = [NSKeyedUnarchiver unarchivedObjectOfClass:MTRCommissioneeInfo.class fromData:data error:NULL]; + XCTAssertNotNil(decoded); + XCTAssertTrue([decoded isEqual:info]); + XCTAssertEqualObjects(decoded.productIdentity, info.productIdentity); + XCTAssertEqualObjects(decoded.endpointsById, info.endpointsById); + XCTAssertEqualObjects(decoded.rootEndpoint.children, info.rootEndpoint.children); + } else { + XCTAssertNil(info.endpointsById); + XCTAssertNil(info.rootEndpoint); + } +} + - (void)controller:(MTRDeviceController *)controller commissioningComplete:(NSError * _Nullable)error { self.commissioningCompleteError = error; @@ -152,20 +187,20 @@ @interface MTRPairingTestMonitoringControllerDelegate : NSObject ", self, MTR_YES_NO(_statusUpdateCalled), MTR_YES_NO(_commissioningSessionEstablishmentDoneCalled), MTR_YES_NO(_commissioningCompleteCalled), MTR_YES_NO(_readCommissioningInfoCalled)]; + return [NSString stringWithFormat:@"", self, MTR_YES_NO(_statusUpdateCalled), MTR_YES_NO(_commissioningSessionEstablishmentDoneCalled), MTR_YES_NO(_commissioningCompleteCalled), MTR_YES_NO(_readCommissioneeInfoCalled)]; } - (void)_checkIfAllCallbacksCalled { if (self.allCallbacksCalledExpectation) { - if (self.statusUpdateCalled && self.commissioningSessionEstablishmentDoneCalled && self.commissioningCompleteCalled && self.readCommissioningInfoCalled) { + if (self.statusUpdateCalled && self.commissioningSessionEstablishmentDoneCalled && self.commissioningCompleteCalled && self.readCommissioneeInfoCalled) { [self.allCallbacksCalledExpectation fulfill]; self.allCallbacksCalledExpectation = nil; } @@ -193,11 +228,12 @@ - (void)controller:(MTRDeviceController *)controller [self _checkIfAllCallbacksCalled]; } -- (void)controller:(MTRDeviceController *)controller readCommissioningInfo:(MTRProductIdentity *)info +- (void)controller:(MTRDeviceController *)controller readCommissioneeInfo:(MTRCommissioneeInfo *)info { - self.readCommissioningInfoCalled = YES; + self.readCommissioneeInfoCalled = YES; [self _checkIfAllCallbacksCalled]; } + @end @interface MTRPairingTests : MTRTestCase @@ -318,7 +354,7 @@ - (void)doPairingTestWithAttestationDelegate:(id)a XCTAssertTrue(monitoringControllerDelegate.statusUpdateCalled); XCTAssertTrue(monitoringControllerDelegate.commissioningSessionEstablishmentDoneCalled); XCTAssertTrue(monitoringControllerDelegate.commissioningCompleteCalled); - XCTAssertTrue(monitoringControllerDelegate.readCommissioningInfoCalled); + XCTAssertTrue(monitoringControllerDelegate.readCommissioneeInfoCalled); [sController removeDeviceControllerDelegate:monitoringControllerDelegate]; } @@ -454,4 +490,29 @@ - (void)test008_pairingAfterCancellation_DeviceAttestationVerification XCTAssertTrue(delegateCalled); } +- (void)test009_PairWithReadingEndpointInformation +{ + [self startServerApp]; + + XCTestExpectation * expectation = [self expectationWithDescription:@"Commissioning Complete"]; + __auto_type * controllerDelegate = [[MTRPairingTestControllerDelegate alloc] initWithExpectation:expectation + attestationDelegate:nil + failSafeExtension:nil]; + + // Endpoint info is validated by MTRPairingTestControllerDelegate + controllerDelegate.shouldReadEndpointInformation = YES; + + dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.pairing", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); + [sController setDeviceControllerDelegate:controllerDelegate queue:callbackQueue]; + self.controllerDelegate = controllerDelegate; + + NSError * error; + __auto_type * payload = [MTRSetupPayload setupPayloadWithOnboardingPayload:kOnboardingPayload error:&error]; + XCTAssertTrue([sController setupCommissioningSessionWithPayload:payload newNodeID:@(++sDeviceId) error:&error]); + XCTAssertNil(error); + + [self waitForExpectations:@[ expectation ] timeout:kPairingTimeoutInSeconds]; + XCTAssertNil(controllerDelegate.commissioningCompleteError); +} + @end diff --git a/src/darwin/Framework/CHIPTests/MTRProductIdentityTests.m b/src/darwin/Framework/CHIPTests/MTRProductIdentityTests.m new file mode 100644 index 00000000000000..e7b7795a8738e0 --- /dev/null +++ b/src/darwin/Framework/CHIPTests/MTRProductIdentityTests.m @@ -0,0 +1,64 @@ +/** + * 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. + */ + +#import +#import + +@interface MTRProductIdentityTests : XCTestCase + +@end + +@implementation MTRProductIdentityTests + +- (void)testEqualityAndCopying +{ + MTRProductIdentity * a1 = [[MTRProductIdentity alloc] initWithVendorID:@1 productID:@1]; + XCTAssertNotNil(a1); + XCTAssertTrue([a1 isEqual:a1]); + XCTAssertTrue([a1 isEqual:[a1 copy]]); + XCTAssertFalse([a1 isEqual:nil]); + XCTAssertFalse([a1 isEqual:@1]); + + MTRProductIdentity * a2 = [[MTRProductIdentity alloc] initWithVendorID:@1 productID:@1]; + XCTAssertNotNil(a2); + XCTAssertTrue([a1 isEqual:a2]); + XCTAssertTrue([a2 isEqual:a1]); + + MTRProductIdentity * b = [[MTRProductIdentity alloc] initWithVendorID:@1 productID:@555]; + XCTAssertNotNil(b); + XCTAssertFalse([b isEqual:a1]); + XCTAssertFalse([a1 isEqual:b]); + + MTRProductIdentity * c = [[MTRProductIdentity alloc] initWithVendorID:@555 productID:@1]; + XCTAssertNotNil(c); + XCTAssertFalse([c isEqual:a1]); + XCTAssertFalse([a1 isEqual:c]); + XCTAssertFalse([c isEqual:b]); + XCTAssertFalse([b isEqual:c]); +} + +- (void)testSecureCoding +{ + MTRProductIdentity * a = [[MTRProductIdentity alloc] initWithVendorID:@123 productID:@42]; + NSData * data = [NSKeyedArchiver archivedDataWithRootObject:a requiringSecureCoding:YES error:NULL]; + MTRProductIdentity * b = [NSKeyedUnarchiver unarchivedObjectOfClass:MTRProductIdentity.class fromData:data error:NULL]; + XCTAssertNotNil(b); + XCTAssertEqualObjects(b.vendorID, a.vendorID); + XCTAssertEqualObjects(b.productID, a.productID); + XCTAssertTrue([b isEqual:a]); +} + +@end diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj index 40be3cfa2c9449..61f5bdf3d3c313 100644 --- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj +++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj @@ -104,6 +104,9 @@ 3CF134AB289D8DF70017A19E /* MTRDeviceAttestationInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CF134AA289D8DF70017A19E /* MTRDeviceAttestationInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3CF134AD289D8E570017A19E /* MTRDeviceAttestationInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3CF134AC289D8E570017A19E /* MTRDeviceAttestationInfo.mm */; }; 3CF134AF289D90FF0017A19E /* MTROperationalCertificateIssuer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3CF134AE289D90FF0017A19E /* MTROperationalCertificateIssuer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3D010DCF2D408FA300CFFA02 /* MTRCommissioneeInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D010DCE2D408FA300CFFA02 /* MTRCommissioneeInfo.mm */; }; + 3D010DD02D408FA300CFFA02 /* MTRCommissioneeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D010DCD2D408FA300CFFA02 /* MTRCommissioneeInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3D010DD22D4091CC00CFFA02 /* MTRCommissioneeInfo_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D010DD12D4091C800CFFA02 /* MTRCommissioneeInfo_Internal.h */; }; 3D0C484B29DA4FA0006D811F /* MTRErrorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D0C484A29DA4FA0006D811F /* MTRErrorTests.m */; }; 3D3928D72BBCEA3D00CDEBB2 /* MTRAvailabilityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D3928D62BBCEA3D00CDEBB2 /* MTRAvailabilityTests.m */; settings = {COMPILER_FLAGS = "-UMTR_NO_AVAILABILITY -Wno-unguarded-availability-new"; }; }; 3D4733AF2BDF1B80003DC19B /* MTRSetupPayloadTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D4733AE2BDF1B80003DC19B /* MTRSetupPayloadTests.m */; }; @@ -116,6 +119,16 @@ 3D843717294979230070D20A /* MTRClusters_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D843715294979230070D20A /* MTRClusters_Internal.h */; }; 3D843756294AD25A0070D20A /* MTRCertificateInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D843754294AD25A0070D20A /* MTRCertificateInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3D843757294AD25A0070D20A /* MTRCertificateInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D843755294AD25A0070D20A /* MTRCertificateInfo.mm */; }; + 3D9F2FBE2D10DB4F003CA2BB /* MTRProductIdentity.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D9F2FBC2D10DB4F003CA2BB /* MTRProductIdentity.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3D9F2FBF2D10DB4F003CA2BB /* MTRProductIdentity.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D9F2FBD2D10DB4F003CA2BB /* MTRProductIdentity.mm */; }; + 3D9F2FC12D10DCA2003CA2BB /* MTRProductIdentityTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D9F2FC02D10DCA2003CA2BB /* MTRProductIdentityTests.m */; }; + 3D9F2FC32D10E207003CA2BB /* MTRDeviceTypeRevisionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D9F2FC22D10E207003CA2BB /* MTRDeviceTypeRevisionTests.m */; }; + 3D9F2FC62D10EA11003CA2BB /* MTREndpointInfo.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D9F2FC52D10EA11003CA2BB /* MTREndpointInfo.mm */; }; + 3D9F2FC72D10EA11003CA2BB /* MTREndpointInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D9F2FC42D10EA11003CA2BB /* MTREndpointInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3D9F2FC92D1105BA003CA2BB /* MTREndpointInfo_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D9F2FC82D1105BA003CA2BB /* MTREndpointInfo_Internal.h */; }; + 3D9F2FCE2D112295003CA2BB /* MTRAttributeTLVValueDecoder_Internal.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3D9F2FCD2D112295003CA2BB /* MTRAttributeTLVValueDecoder_Internal.mm */; }; + 3D9F2FD02D11FE90003CA2BB /* MTREndpointInfoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3D9F2FCF2D11FE90003CA2BB /* MTREndpointInfoTests.m */; }; + 3D9F2FD22D11FF27003CA2BB /* MTREndpointInfo_Test.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D9F2FD12D11FF27003CA2BB /* MTREndpointInfo_Test.h */; }; 3DA1A3552ABAB3B4004F0BB9 /* MTRAsyncWorkQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 3DA1A3522ABAB3B4004F0BB9 /* MTRAsyncWorkQueue.h */; }; 3DA1A3562ABAB3B4004F0BB9 /* MTRAsyncWorkQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3DA1A3532ABAB3B4004F0BB9 /* MTRAsyncWorkQueue.mm */; }; 3DA1A3582ABABF6A004F0BB9 /* MTRAsyncWorkQueueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DA1A3572ABABF69004F0BB9 /* MTRAsyncWorkQueueTests.m */; }; @@ -580,6 +593,9 @@ 3CF134AA289D8DF70017A19E /* MTRDeviceAttestationInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRDeviceAttestationInfo.h; sourceTree = ""; }; 3CF134AC289D8E570017A19E /* MTRDeviceAttestationInfo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRDeviceAttestationInfo.mm; sourceTree = ""; }; 3CF134AE289D90FF0017A19E /* MTROperationalCertificateIssuer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTROperationalCertificateIssuer.h; sourceTree = ""; }; + 3D010DCD2D408FA300CFFA02 /* MTRCommissioneeInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRCommissioneeInfo.h; sourceTree = ""; }; + 3D010DCE2D408FA300CFFA02 /* MTRCommissioneeInfo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRCommissioneeInfo.mm; sourceTree = ""; }; + 3D010DD12D4091C800CFFA02 /* MTRCommissioneeInfo_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRCommissioneeInfo_Internal.h; sourceTree = ""; }; 3D0C484A29DA4FA0006D811F /* MTRErrorTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRErrorTests.m; sourceTree = ""; }; 3D3928D62BBCEA3D00CDEBB2 /* MTRAvailabilityTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRAvailabilityTests.m; sourceTree = ""; }; 3D4733AE2BDF1B80003DC19B /* MTRSetupPayloadTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRSetupPayloadTests.m; sourceTree = ""; }; @@ -611,6 +627,16 @@ 3D84372F294984AF0070D20A /* command_completion_type.zapt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = command_completion_type.zapt; sourceTree = ""; }; 3D843754294AD25A0070D20A /* MTRCertificateInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRCertificateInfo.h; sourceTree = ""; }; 3D843755294AD25A0070D20A /* MTRCertificateInfo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRCertificateInfo.mm; sourceTree = ""; }; + 3D9F2FBC2D10DB4F003CA2BB /* MTRProductIdentity.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRProductIdentity.h; sourceTree = ""; }; + 3D9F2FBD2D10DB4F003CA2BB /* MTRProductIdentity.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRProductIdentity.mm; sourceTree = ""; }; + 3D9F2FC02D10DCA2003CA2BB /* MTRProductIdentityTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRProductIdentityTests.m; sourceTree = ""; }; + 3D9F2FC22D10E207003CA2BB /* MTRDeviceTypeRevisionTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTRDeviceTypeRevisionTests.m; sourceTree = ""; }; + 3D9F2FC42D10EA11003CA2BB /* MTREndpointInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTREndpointInfo.h; sourceTree = ""; }; + 3D9F2FC52D10EA11003CA2BB /* MTREndpointInfo.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTREndpointInfo.mm; sourceTree = ""; }; + 3D9F2FC82D1105BA003CA2BB /* MTREndpointInfo_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTREndpointInfo_Internal.h; sourceTree = ""; }; + 3D9F2FCD2D112295003CA2BB /* MTRAttributeTLVValueDecoder_Internal.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRAttributeTLVValueDecoder_Internal.mm; sourceTree = ""; }; + 3D9F2FCF2D11FE90003CA2BB /* MTREndpointInfoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MTREndpointInfoTests.m; sourceTree = ""; }; + 3D9F2FD12D11FF27003CA2BB /* MTREndpointInfo_Test.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTREndpointInfo_Test.h; sourceTree = ""; }; 3DA1A3522ABAB3B4004F0BB9 /* MTRAsyncWorkQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MTRAsyncWorkQueue.h; sourceTree = ""; }; 3DA1A3532ABAB3B4004F0BB9 /* MTRAsyncWorkQueue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MTRAsyncWorkQueue.mm; sourceTree = ""; }; 3DA1A3572ABABF69004F0BB9 /* MTRAsyncWorkQueueTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MTRAsyncWorkQueueTests.m; sourceTree = ""; }; @@ -1340,8 +1366,6 @@ 51D0B1362B618CC6006E3511 /* MTRServerAttribute.h */, 51D0B1372B618CC6006E3511 /* MTRServerAttribute.mm */, 514C79FF2B64223400DD6D7B /* MTRServerAttribute_Internal.h */, - 51D0B13A2B61B2F2006E3511 /* MTRDeviceTypeRevision.h */, - 51D0B13B2B61B2F2006E3511 /* MTRDeviceTypeRevision.mm */, 51D0B1262B617246006E3511 /* MTRServerEndpoint.h */, 51D0B1252B617246006E3511 /* MTRServerEndpoint.mm */, 514C7A002B64223400DD6D7B /* MTRServerEndpoint_Internal.h */, @@ -1453,6 +1477,7 @@ 27A53C1527FBC6920053F131 /* MTRAttestationTrustStoreBridge.h */, 27A53C1627FBC6920053F131 /* MTRAttestationTrustStoreBridge.mm */, 513DDB852761F69300DAA01A /* MTRAttributeTLVValueDecoder_Internal.h */, + 3D9F2FCD2D112295003CA2BB /* MTRAttributeTLVValueDecoder_Internal.mm */, 75B765C02A1D71BC0014719B /* MTRAttributeSpecifiedCheck.h */, 51EF279E2A2A3EB100E33F75 /* MTRBackwardsCompatShims.h */, 510470FA2A2F7DF60053EA7E /* MTRBackwardsCompatShims.mm */, @@ -1477,6 +1502,9 @@ 5178E67F2AE098510069DF72 /* MTRCommandTimedCheck.h */, 51FE723E2ACDEF3E00437032 /* MTRCommandPayloadExtensions_Internal.h */, 5178E6802AE098520069DF72 /* MTRCommissionableBrowserResult_Internal.h */, + 3D010DCD2D408FA300CFFA02 /* MTRCommissioneeInfo.h */, + 3D010DD12D4091C800CFFA02 /* MTRCommissioneeInfo_Internal.h */, + 3D010DCE2D408FA300CFFA02 /* MTRCommissioneeInfo.mm */, 99D466E02798936D0089A18F /* MTRCommissioningParameters.h */, 99AECC7F2798A57E00B6355B /* MTRCommissioningParameters.mm */, 3DFCB32B29678C9500332B35 /* MTRConversion.h */, @@ -1546,6 +1574,12 @@ 51F522692AE70761000C4050 /* MTRDeviceTypeMetadata.h */, 5109E9B22CB8B5DF0006884B /* MTRDeviceType.h */, 5109E9B32CB8B5DF0006884B /* MTRDeviceType.mm */, + 51D0B13A2B61B2F2006E3511 /* MTRDeviceTypeRevision.h */, + 51D0B13B2B61B2F2006E3511 /* MTRDeviceTypeRevision.mm */, + 3D9F2FC42D10EA11003CA2BB /* MTREndpointInfo.h */, + 3D9F2FD12D11FF27003CA2BB /* MTREndpointInfo_Test.h */, + 3D9F2FC82D1105BA003CA2BB /* MTREndpointInfo_Internal.h */, + 3D9F2FC52D10EA11003CA2BB /* MTREndpointInfo.mm */, 5129BCFC26A9EE3300122DDF /* MTRError.h */, B2E0D7AB245B0B5C003C5B48 /* MTRError_Internal.h */, 51578AEA2D0B9DC0001716FF /* MTRError_Testable.h */, @@ -1576,6 +1610,8 @@ 998F287026D56940001846C6 /* MTRP256KeypairBridge.mm */, 2C8C8FBD253E0C2100797F05 /* MTRPersistentStorageDelegateBridge.h */, 2C8C8FBF253E0C2100797F05 /* MTRPersistentStorageDelegateBridge.mm */, + 3D9F2FBC2D10DB4F003CA2BB /* MTRProductIdentity.h */, + 3D9F2FBD2D10DB4F003CA2BB /* MTRProductIdentity.mm */, 514654482A72F9DF00904E61 /* MTRDemuxingStorage.mm */, 5146544A2A72F9F500904E61 /* MTRDemuxingStorage.h */, 51E95DF92A78443C00A434F0 /* MTRSessionResumptionStorageBridge.h */, @@ -1625,7 +1661,9 @@ 5AE6D4E327A99041001F2493 /* MTRDeviceTests.m */, 75B326A12BCF12E900E17C4E /* MTRDeviceConnectivityMonitorTests.m */, 5109E9B62CB8B83D0006884B /* MTRDeviceTypeTests.m */, + 3D9F2FC22D10E207003CA2BB /* MTRDeviceTypeRevisionTests.m */, 51D9CB0A2BA37DCE0049D6DB /* MTRDSTOffsetTests.m */, + 3D9F2FCF2D11FE90003CA2BB /* MTREndpointInfoTests.m */, 3D0C484A29DA4FA0006D811F /* MTRErrorTests.m */, 51578AE82D0B9B1D001716FF /* MTRErrorMappingTests.m */, 5173A47829C0E82300F67F48 /* MTRFabricInfoTests.m */, @@ -1634,6 +1672,7 @@ 5142E39729D377F000A206F0 /* MTROTAProviderTests.m */, 51742B4D29CB6B88009974FE /* MTRPairingTests.m */, 51E95DF72A78110900A434F0 /* MTRPerControllerStorageTests.m */, + 3D9F2FC02D10DCA2003CA2BB /* MTRProductIdentityTests.m */, 51D0B1292B61766F006E3511 /* MTRServerEndpointTests.m */, 3D4733AE2BDF1B80003DC19B /* MTRSetupPayloadTests.m */, 519498312A25581C00B3BABE /* MTRSetupPayloadInitializationTests.m */, @@ -1831,6 +1870,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 3D9F2FBE2D10DB4F003CA2BB /* MTRProductIdentity.h in Headers */, 51D0B1282B617246006E3511 /* MTRServerEndpoint.h in Headers */, 51565CB62A7B0D6600469F18 /* MTRDeviceControllerParameters.h in Headers */, 51565CB42A7AD78D00469F18 /* MTRDeviceControllerStorageDelegate.h in Headers */, @@ -1907,6 +1947,7 @@ 3D843756294AD25A0070D20A /* MTRCertificateInfo.h in Headers */, 7596A83E28751220004DAE0E /* MTRBaseClusters_Internal.h in Headers */, 997DED182695344800975E97 /* MTRThreadOperationalDataset.h in Headers */, + 3D010DD02D408FA300CFFA02 /* MTRCommissioneeInfo.h in Headers */, 9956064426420367000C28DE /* MTRSetupPayload_Internal.h in Headers */, 27A53C1727FBC6920053F131 /* MTRAttestationTrustStoreBridge.h in Headers */, 5A830D6C27CFCF590053B85D /* MTRDeviceControllerOverXPC_Internal.h in Headers */, @@ -1915,6 +1956,7 @@ 514C7A012B64223400DD6D7B /* MTRServerAttribute_Internal.h in Headers */, 3DFCB32C29678C9500332B35 /* MTRConversion.h in Headers */, 5A60370827EA1FF60020DB79 /* MTRClusterStateCacheContainer+XPC.h in Headers */, + 3D9F2FC92D1105BA003CA2BB /* MTREndpointInfo_Internal.h in Headers */, 5ACDDD7E27CD3F3A00EFD68A /* MTRClusterStateCacheContainer_Internal.h in Headers */, 5136661328067D550025EDAE /* MTRDeviceController_Internal.h in Headers */, 998F286D26D55E10001846C6 /* MTRKeypair.h in Headers */, @@ -1943,6 +1985,7 @@ 9B231B042C62EF650030EB37 /* (null) in Headers */, 515BE4ED2B72C0C5000BC1FD /* MTRUnfairLock.h in Headers */, 998F286F26D55EC5001846C6 /* MTRP256KeypairBridge.h in Headers */, + 3D9F2FC72D10EA11003CA2BB /* MTREndpointInfo.h in Headers */, CF3B63CF2CA31E71003C1C87 /* MTROTAImageTransferHandler.h in Headers */, 2C222ADF255C811800E446B9 /* MTRBaseDevice_Internal.h in Headers */, 514C7A022B64223400DD6D7B /* MTRServerEndpoint_Internal.h in Headers */, @@ -1951,6 +1994,7 @@ 3D843713294977000070D20A /* NSDataSpanConversion.h in Headers */, 9B5CCB5D2C6EC890009DD99B /* MTRDevice_XPC.h in Headers */, 991DC08B247704DC00C13860 /* MTRLogging_Internal.h in Headers */, + 3D010DD22D4091CC00CFFA02 /* MTRCommissioneeInfo_Internal.h in Headers */, 51FE723F2ACDEF3E00437032 /* MTRCommandPayloadExtensions_Internal.h in Headers */, 51578AEB2D0B9DC0001716FF /* MTRError_Testable.h in Headers */, 51D0B12E2B6177FD006E3511 /* MTRAccessGrant.h in Headers */, @@ -1960,6 +2004,7 @@ 7592BCF42CBEE98C00EB74A0 /* EmberMetadata.h in Headers */, 7592BCF52CBEE98C00EB74A0 /* CodegenDataModelProvider.h in Headers */, 7596A84828762783004DAE0E /* MTRAsyncCallbackWorkQueue.h in Headers */, + 3D9F2FD22D11FF27003CA2BB /* MTREndpointInfo_Test.h in Headers */, 5A7947E527C0129F00434CF2 /* MTRDeviceController+XPC.h in Headers */, 51E95DFB2A78443C00A434F0 /* MTRSessionResumptionStorageBridge.h in Headers */, B2E0D7B4245B0B5C003C5B48 /* MTRError_Internal.h in Headers */, @@ -2255,6 +2300,7 @@ 7592BCF82CBEE98C00EB74A0 /* EmberMetadata.cpp in Sources */, 7592BCF92CBEE98C00EB74A0 /* CodegenDataModelProvider.cpp in Sources */, 7592BCFA2CBEE98C00EB74A0 /* CodegenDataModelProvider_Write.cpp in Sources */, + 3D010DCF2D408FA300CFFA02 /* MTRCommissioneeInfo.mm in Sources */, 93B2CF9A2B56E45C00E4D187 /* MTRClusterNames.mm in Sources */, 998F287126D56940001846C6 /* MTRP256KeypairBridge.mm in Sources */, 516416012B6B483C00D5CE11 /* MTRIMDispatch.mm in Sources */, @@ -2292,6 +2338,7 @@ CF3B63D12CA31E71003C1C87 /* MTROTAImageTransferHandler.mm in Sources */, 51D0B12F2B617800006E3511 /* MTRAccessGrant.mm in Sources */, 88E6C9482B6334ED001A1FE0 /* MTRMetrics.mm in Sources */, + 3D9F2FBF2D10DB4F003CA2BB /* MTRProductIdentity.mm in Sources */, 1ED276E226C5812A00547A89 /* MTRCluster.mm in Sources */, 9BFE5D512C6D3075007D4319 /* MTRDeviceController_XPC.mm in Sources */, 514A98B12CD98C5E000EF4FD /* MTRAttributeValueWaiter.mm in Sources */, @@ -2308,12 +2355,14 @@ 5ACDDD7D27CD16D200EFD68A /* MTRClusterStateCacheContainer.mm in Sources */, 75B3269E2BCDB9EA00E17C4E /* MTRDeviceConnectivityMonitor.mm in Sources */, 7534D1802CF8CE2000F64654 /* DefaultAttributePersistenceProvider.cpp in Sources */, + 3D9F2FC62D10EA11003CA2BB /* MTREndpointInfo.mm in Sources */, 9B5CCB5C2C6EC890009DD99B /* MTRDevice_XPC.mm in Sources */, 513DDB8A2761F6F900DAA01A /* MTRAttributeTLVValueDecoder.mm in Sources */, 5117DD3829A931AE00FFA1AA /* MTROperationalBrowser.mm in Sources */, 514C79F02B62ADDA00DD6D7B /* descriptor.cpp in Sources */, 5109E9B42CB8B5DF0006884B /* MTRDeviceType.mm in Sources */, 3D843757294AD25A0070D20A /* MTRCertificateInfo.mm in Sources */, + 3D9F2FCE2D112295003CA2BB /* MTRAttributeTLVValueDecoder_Internal.mm in Sources */, 5A7947E427C0129600434CF2 /* MTRDeviceController+XPC.mm in Sources */, 7592BD0B2CC6BCC300EB74A0 /* EmberAttributeDataBuffer.cpp in Sources */, 5A6FEC9027B563D900F25F42 /* MTRDeviceControllerOverXPC.mm in Sources */, @@ -2370,7 +2419,9 @@ 518D3F832AA132DC008E0007 /* MTRTestPerControllerStorage.m in Sources */, 51339B1F2A0DA64D00C798C1 /* MTRCertificateValidityTests.m in Sources */, 5173A47929C0E82300F67F48 /* MTRFabricInfoTests.m in Sources */, + 3D9F2FC12D10DCA2003CA2BB /* MTRProductIdentityTests.m in Sources */, 75B326A22BCF12E900E17C4E /* MTRDeviceConnectivityMonitorTests.m in Sources */, + 3D9F2FD02D11FE90003CA2BB /* MTREndpointInfoTests.m in Sources */, 5143851E2A65885500EDC8E6 /* MTRSwiftPairingTests.swift in Sources */, 75B0D01E2B71B47F002074DD /* MTRDeviceTestDelegate.m in Sources */, 3D0C484B29DA4FA0006D811F /* MTRErrorTests.m in Sources */, @@ -2383,6 +2434,7 @@ 51F9F9D52BF7A9EE00FEA0E2 /* MTRTestCase+ServerAppRunner.m in Sources */, 517BF3F3282B62CB00A8B7DB /* MTRCertificateTests.m in Sources */, 5142E39829D377F000A206F0 /* MTROTAProviderTests.m in Sources */, + 3D9F2FC32D10E207003CA2BB /* MTRDeviceTypeRevisionTests.m in Sources */, 51E0FC102ACBBF230001E197 /* MTRSwiftDeviceTests.swift in Sources */, 3D4733AF2BDF1B80003DC19B /* MTRSetupPayloadTests.m in Sources */, 5109E9B72CB8B83D0006884B /* MTRDeviceTypeTests.m in Sources */, From 080185d9450cecad30cd2fce27663019ab2f16a1 Mon Sep 17 00:00:00 2001 From: Shubham Patil Date: Fri, 24 Jan 2025 15:54:11 +0530 Subject: [PATCH 23/40] da_revocation: user guide and dac_provider test vectors (#37122) * da_revocation: added dac_provider test vectors These test vectors support testing with sample revocation sets. * dac_revocation: device attestation revocation user guide This document lists the process for testing device attestation revocation using the dac provider test vectors sample revocation sets. * Restyled by whitespace * Restyled by prettier-markdown * Match the enum string with correct value in the doc --------- Co-authored-by: Restyled.io --- .../revoked-dac-01.json | 9 ++++ .../revoked-dac-02.json | 9 ++++ .../revoked-dac-03.json | 9 ++++ .../revoked-pai.json | 9 ++++ .../device-attestation-revocation-guide.md | 52 +++++++++++++++++++ 5 files changed, 88 insertions(+) create mode 100644 credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-01.json create mode 100644 credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-02.json create mode 100644 credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-03.json create mode 100644 credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-pai.json create mode 100644 docs/guides/device-attestation-revocation-guide.md diff --git a/credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-01.json b/credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-01.json new file mode 100644 index 00000000000000..05dc6b0cc80dcb --- /dev/null +++ b/credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-01.json @@ -0,0 +1,9 @@ +{ + "description": "Revoked DAC 01: use this with revocation-sets/revocation-set-for-pai.json", + "basic_info_pid": 32769, + "certification_declaration": "3081e706092a864886f70d010702a081d93081d6020103310d300b0609608648016503040201304306092a864886f70d010701a0360434152400012501f1ff3602050180182403162c0413435341303030303053574330303030302d303124050024060024070124080018317d307b020103801462fa823359acfaa9963e1cfa140addf504f37160300b0609608648016503040201300a06082a8648ce3d0403020447304502204dc6be89beeb5a49adec51ee7f0e6d1263ffc9e6238f2044385a5e0c86751b83022100ed902842f7a5784368d63eba6a2fb90086dd65a0ce3c283d86b915a3536afdac", + "pai_cert": "308201cb30820171a003020102020856ad8222ad945b64300a06082a8648ce3d04030230303118301606035504030c0f4d617474657220546573742050414131143012060a2b0601040182a27c02010c04464646313020170d3232303230353030303030305a180f39393939313233313233353935395a303d3125302306035504030c1c4d6174746572204465762050414920307846464631206e6f2050494431143012060a2b0601040182a27c02010c04464646313059301306072a8648ce3d020106082a8648ce3d03010703420004419a9315c2173e0c8c876d03ccfc944852647f7fec5e5082f4059928eca894c594151309ac631e4cb03392af684b0bafb7e65b3b8162c2f52bf931b8e77aaa82a366306430120603551d130101ff040830060101ff020100300e0603551d0f0101ff040403020106301d0603551d0e0416041463540e47f64b1c38d13884a462d16c195d8ffb3c301f0603551d230418301680146afd22771f511fecbf1641976710dcdc31a1717e300a06082a8648ce3d0403020348003045022100b2ef27f49ae9b50fb91eeac94c4d0bdbb8d7929c6cb88face529368d12054c0c0220655dc92b86bd909882a6c62177b825d7d05edbe7c22f9fea71220e7ea703f891", + "dac_cert": "308201e53082018ba003020102020819367d978eac533a300a06082a8648ce3d040302303d3125302306035504030c1c4d6174746572204465762050414920307846464631206e6f2050494431143012060a2b0601040182a27c02010c04464646313020170d3234313231333030303030305a180f39393939313233313233353935395a30503122302006035504030c194d61747465722044657620444143205265766f6b656420303131143012060a2b0601040182a27c02010c044646463131143012060a2b0601040182a27c02020c04383030313059301306072a8648ce3d020106082a8648ce3d030107034200042a3d7370f2209bb139b42ca6d95dbf2f701888b4718e32c63ae71327145e05187868b528f1a99d246f1470b0ccd855ee94383526ee090de0bb2fde038fee3e0ba360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414f58ae953a4e6cfb0cc3de4dc4c33afe097aa1182301f0603551d2304183016801463540e47f64b1c38d13884a462d16c195d8ffb3c300a06082a8648ce3d0403020348003045022018336444494d4d18c7814b6f3b0f3f7fa5dd21256515031da31fd7ff8d1b10fd022100e75cbf171a38907a932a1679e5d5b423e6a166729d823fec844f22ef398912a4", + "dac_private_key": "246eea662a44cb6de93effd614e96d3715de8cfb6d4e975644ee5e66ecb79c79", + "dac_public_key": "042a3d7370f2209bb139b42ca6d95dbf2f701888b4718e32c63ae71327145e05187868b528f1a99d246f1470b0ccd855ee94383526ee090de0bb2fde038fee3e0b" +} diff --git a/credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-02.json b/credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-02.json new file mode 100644 index 00000000000000..ab3f927e8bd3ae --- /dev/null +++ b/credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-02.json @@ -0,0 +1,9 @@ +{ + "description": "Revoked DAC 02: use this with revocation-sets/revocation-set-for-pai.json", + "basic_info_pid": 32769, + "certification_declaration": "3081e706092a864886f70d010702a081d93081d6020103310d300b0609608648016503040201304306092a864886f70d010701a0360434152400012501f1ff3602050180182403162c0413435341303030303053574330303030302d303124050024060024070124080018317d307b020103801462fa823359acfaa9963e1cfa140addf504f37160300b0609608648016503040201300a06082a8648ce3d0403020447304502204dc6be89beeb5a49adec51ee7f0e6d1263ffc9e6238f2044385a5e0c86751b83022100ed902842f7a5784368d63eba6a2fb90086dd65a0ce3c283d86b915a3536afdac", + "pai_cert": "308201cb30820171a003020102020856ad8222ad945b64300a06082a8648ce3d04030230303118301606035504030c0f4d617474657220546573742050414131143012060a2b0601040182a27c02010c04464646313020170d3232303230353030303030305a180f39393939313233313233353935395a303d3125302306035504030c1c4d6174746572204465762050414920307846464631206e6f2050494431143012060a2b0601040182a27c02010c04464646313059301306072a8648ce3d020106082a8648ce3d03010703420004419a9315c2173e0c8c876d03ccfc944852647f7fec5e5082f4059928eca894c594151309ac631e4cb03392af684b0bafb7e65b3b8162c2f52bf931b8e77aaa82a366306430120603551d130101ff040830060101ff020100300e0603551d0f0101ff040403020106301d0603551d0e0416041463540e47f64b1c38d13884a462d16c195d8ffb3c301f0603551d230418301680146afd22771f511fecbf1641976710dcdc31a1717e300a06082a8648ce3d0403020348003045022100b2ef27f49ae9b50fb91eeac94c4d0bdbb8d7929c6cb88face529368d12054c0c0220655dc92b86bd909882a6c62177b825d7d05edbe7c22f9fea71220e7ea703f891", + "dac_cert": "308201e53082018ba00302010202082569383d24bb36ea300a06082a8648ce3d040302303d3125302306035504030c1c4d6174746572204465762050414920307846464631206e6f2050494431143012060a2b0601040182a27c02010c04464646313020170d3234313231333030303030305a180f39393939313233313233353935395a30503122302006035504030c194d61747465722044657620444143205265766f6b656420303231143012060a2b0601040182a27c02010c044646463131143012060a2b0601040182a27c02020c04383030313059301306072a8648ce3d020106082a8648ce3d03010703420004d9713c48a59527e93e7a3e549e8fb0e00829d4a02c8cedf28dfd74672b00198c7ee43f35e3ace1d1ab497b32dde4cdd6a8476162191c9514aef7bf115fb6c472a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e04160414e3af9182b3340fdc85c7a58b4b3884a6554b314f301f0603551d2304183016801463540e47f64b1c38d13884a462d16c195d8ffb3c300a06082a8648ce3d0403020348003045022100afbe8ff0962e875a3054ee5a2df5c4c78c05465b40d3103f99f7e5628780f90302201a6157f0df7823223ae24aa3a8f7a6137b4914c6b6f5e40a297d7ab771e9cbc6", + "dac_private_key": "22f8d19a6b524130eccad5d187ce8eb7ea9d7ffd5868b4e0ca91bc2b6c84399c", + "dac_public_key": "04d9713c48a59527e93e7a3e549e8fb0e00829d4a02c8cedf28dfd74672b00198c7ee43f35e3ace1d1ab497b32dde4cdd6a8476162191c9514aef7bf115fb6c472" +} diff --git a/credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-03.json b/credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-03.json new file mode 100644 index 00000000000000..a629f86bd5708c --- /dev/null +++ b/credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-03.json @@ -0,0 +1,9 @@ +{ + "description": "Revoked DAC 03: use this with revocation-sets/revocation-set-for-pai.json", + "basic_info_pid": 32769, + "certification_declaration": "3081e706092a864886f70d010702a081d93081d6020103310d300b0609608648016503040201304306092a864886f70d010701a0360434152400012501f1ff3602050180182403162c0413435341303030303053574330303030302d303124050024060024070124080018317d307b020103801462fa823359acfaa9963e1cfa140addf504f37160300b0609608648016503040201300a06082a8648ce3d0403020447304502204dc6be89beeb5a49adec51ee7f0e6d1263ffc9e6238f2044385a5e0c86751b83022100ed902842f7a5784368d63eba6a2fb90086dd65a0ce3c283d86b915a3536afdac", + "pai_cert": "308201cb30820171a003020102020856ad8222ad945b64300a06082a8648ce3d04030230303118301606035504030c0f4d617474657220546573742050414131143012060a2b0601040182a27c02010c04464646313020170d3232303230353030303030305a180f39393939313233313233353935395a303d3125302306035504030c1c4d6174746572204465762050414920307846464631206e6f2050494431143012060a2b0601040182a27c02010c04464646313059301306072a8648ce3d020106082a8648ce3d03010703420004419a9315c2173e0c8c876d03ccfc944852647f7fec5e5082f4059928eca894c594151309ac631e4cb03392af684b0bafb7e65b3b8162c2f52bf931b8e77aaa82a366306430120603551d130101ff040830060101ff020100300e0603551d0f0101ff040403020106301d0603551d0e0416041463540e47f64b1c38d13884a462d16c195d8ffb3c301f0603551d230418301680146afd22771f511fecbf1641976710dcdc31a1717e300a06082a8648ce3d0403020348003045022100b2ef27f49ae9b50fb91eeac94c4d0bdbb8d7929c6cb88face529368d12054c0c0220655dc92b86bd909882a6c62177b825d7d05edbe7c22f9fea71220e7ea703f891", + "dac_cert": "308201e63082018ba00302010202080ab042494323fe54300a06082a8648ce3d040302303d3125302306035504030c1c4d6174746572204465762050414920307846464631206e6f2050494431143012060a2b0601040182a27c02010c04464646313020170d3234313231333030303030305a180f39393939313233313233353935395a30503122302006035504030c194d61747465722044657620444143205265766f6b656420303331143012060a2b0601040182a27c02010c044646463131143012060a2b0601040182a27c02020c04383030313059301306072a8648ce3d020106082a8648ce3d0301070342000422e57365e98990ff7506e11ebec33ff834a39999f2d9d635ef5847ebe058d87d1bfbe1e5e2411bb6dc11f3f27e842cc0ccabe02a4f269d50f5ca072a2635db04a360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e041604142ad1e7d3f1480029366ee4c5f07107f24a9d9bad301f0603551d2304183016801463540e47f64b1c38d13884a462d16c195d8ffb3c300a06082a8648ce3d0403020349003046022100e66960cc3b6ea61f8830bf788830166b5c6a318e83284604a95bc2655bd874eb022100f503806797a512ab509312e8082fc828622696d3d7501f7f3e68b61abfe5bdb8", + "dac_private_key": "98c2d8b375f1d792e572c701b4740e7fb81a9e9cc936aa2a0f876ce8dae5578c", + "dac_public_key": "0422e57365e98990ff7506e11ebec33ff834a39999f2d9d635ef5847ebe058d87d1bfbe1e5e2411bb6dc11f3f27e842cc0ccabe02a4f269d50f5ca072a2635db04" +} diff --git a/credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-pai.json b/credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-pai.json new file mode 100644 index 00000000000000..9f20a423330974 --- /dev/null +++ b/credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-pai.json @@ -0,0 +1,9 @@ +{ + "description": "Revoked PAI: use this with revocation-sets/revocation-set-for-paa.json", + "basic_info_pid": 32769, + "certification_declaration": "3081e706092a864886f70d010702a081d93081d6020103310d300b0609608648016503040201304306092a864886f70d010701a0360434152400012501f1ff3602050180182403162c0413435341303030303053574330303030302d303124050024060024070124080018317d307b020103801462fa823359acfaa9963e1cfa140addf504f37160300b0609608648016503040201300a06082a8648ce3d0403020447304502204dc6be89beeb5a49adec51ee7f0e6d1263ffc9e6238f2044385a5e0c86751b83022100ed902842f7a5784368d63eba6a2fb90086dd65a0ce3c283d86b915a3536afdac", + "pai_cert": "308201d43082017aa0030201020208302664392b8a3f2a300a06082a8648ce3d04030230303118301606035504030c0f4d617474657220546573742050414131143012060a2b0601040182a27c02010c04464646313020170d3234313231333030303030305a180f39393939313233313233353935395a3046312e302c06035504030c254d617474657220546573742050414920307846464631206e6f20504944205265766f6b656431143012060a2b0601040182a27c02010c04464646313059301306072a8648ce3d020106082a8648ce3d03010703420004bd58a84f7862e0751c4e56280f149697df7c51aadc5a4fa393c96277a59079de40907ab7860d069de652ea8bc8f7053bfe7c3a8ef4700d76b9cc20db312caf91a366306430120603551d130101ff040830060101ff020100300e0603551d0f0101ff040403020106301d0603551d0e0416041491337c5cfe7bb29376fe887d3c94e7f59dd83d2f301f0603551d230418301680146afd22771f511fecbf1641976710dcdc31a1717e300a06082a8648ce3d04030203480030450221009c74f6a84b3acb5a369de90399114ebf0a55150babd3d52b2898708847bc9c6e0220651881c81b7a20c346b97c68313c4be1c0a88f4f3a4072ed3c7ea11dc60984fc", + "dac_cert": "308201e33082018aa00302010202087f1c17c6070c22d2300a06082a8648ce3d0403023046312e302c06035504030c254d617474657220546573742050414920307846464631206e6f20504944205265766f6b656431143012060a2b0601040182a27c02010c04464646313020170d3234313231333030303030305a180f39393939313233313233353935395a30463118301606035504030c0f4d617474657220546573742044414331143012060a2b0601040182a27c02010c044646463131143012060a2b0601040182a27c02020c04383030313059301306072a8648ce3d020106082a8648ce3d03010703420004b0d7f20c57c8240b975456ba886d2cb09cd4f9d2f5cf1406f463c97983f34ed5a36761f696d8aff4f3e282865bc37914deb512aae88e5a15a719a4b57a26640fa360305e300c0603551d130101ff04023000300e0603551d0f0101ff040403020780301d0603551d0e0416041438248c0e17b222347e42aab9af3fdc1d3d614904301f0603551d2304183016801491337c5cfe7bb29376fe887d3c94e7f59dd83d2f300a06082a8648ce3d040302034700304402202bf8b3b554efe5b53f6612891a9a9e6cb7267a55257ef3414929b259d1b7a2e102206dcfd0d84ad5a32c9bd05eec4a1b0ff7a435feed4bc540f087b81f6ec5009ba2", + "dac_private_key": "91fa91640fee5dcc5ab56decb1cb4d2e0056c16b45283104c0c849ec13dcceef", + "dac_public_key": "04b0d7f20c57c8240b975456ba886d2cb09cd4f9d2f5cf1406f463c97983f34ed5a36761f696d8aff4f3e282865bc37914deb512aae88e5a15a719a4b57a26640f" +} diff --git a/docs/guides/device-attestation-revocation-guide.md b/docs/guides/device-attestation-revocation-guide.md new file mode 100644 index 00000000000000..6ee4fee8461c23 --- /dev/null +++ b/docs/guides/device-attestation-revocation-guide.md @@ -0,0 +1,52 @@ +# Device Attestation Revocation Testing Guide + +## Overview + +The device attestation revocation tests help identify the devices with revoked +DACs (Device Attestation Certificates) and PAIs (Product Attestation +Intermediates) during commissioning. + +This guide demonstrates how to use a sample application and chip-tool to test +the device attestation revocation functionality. + +The sample application is injected with revoked DAC and/or PAI certificates. + +During commissioning, chip-tool is provided with a revocation set that is +pre-generated using the `generate_revocation_set.py` script. + +## Prerequisites + +- Matter application for Linux platform (e.g., examples/lighting-app/linux) +- DAC provider JSON file containing revoked DAC and/or PAI certificates +- chip-tool +- Device attestation revocation set for the respective DAC and/or PAI + +## Test Setup + +- Build the lighting-app/linux and chip-tool: + +``` +./scripts/examples/gn_build_example.sh examples/lighting-app/linux out/host +./scripts/examples/gn_build_example.sh examples/chip-tool out/host +``` + +- Run the lighting-app/linux: + +``` +./out/host/chip-lighting-app --dac_provider +``` + +- Run the chip-tool with the revocation set: + +``` +./out/host/chip-tool pairing onnetwork 11 20202021 --dac-revocation-set-path +``` + +### Test Vectors + +| Description | DAC Provider | Revocation Set | Expected Result | +| --------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | +| PAI revoked by PAA | [revoked-pai.json](../../credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-pai.json) | [revocation-set-for-paa.json](../../credentials/test/revoked-attestation-certificates/revocation-sets/revocation-set-for-paa.json) | Commissioning fails with `kPaiRevoked` (202) | +| DAC-01 revoked by PAI | [revoked-dac-01.json](../../credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-01.json) | [revocation-set-for-pai.json](../../credentials/test/revoked-attestation-certificates/revocation-sets/revocation-set-for-pai.json) | Commissioning fails with `kDacRevoked` (302) | +| DAC-02 revoked by PAI | [revoked-dac-02.json](../../credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-02.json) | [revocation-set-for-pai.json](../../credentials/test/revoked-attestation-certificates/revocation-sets/revocation-set-for-pai.json) | Commissioning fails with `kDacRevoked` (302) | +| DAC-03 revoked by PAI | [revoked-dac-03.json](../../credentials/test/revoked-attestation-certificates/dac-provider-test-vectors/revoked-dac-03.json) | [revocation-set-for-pai.json](../../credentials/test/revoked-attestation-certificates/revocation-sets/revocation-set-for-pai.json) | Commissioning fails with `kDacRevoked` (302) | From 2b020e0d17d3546993cee0015e3b612b7b009a80 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Fri, 24 Jan 2025 04:17:12 -0800 Subject: [PATCH 24/40] Treat a Nullable attribute as raw type if it is not NullValue (#37182) --- src/python_testing/TC_DGWIFI_2_1.py | 66 +++++++++-------------------- src/python_testing/TC_DGWIFI_2_3.py | 5 +-- 2 files changed, 22 insertions(+), 49 deletions(-) diff --git a/src/python_testing/TC_DGWIFI_2_1.py b/src/python_testing/TC_DGWIFI_2_1.py index 2320385da0a763..e32f1487291263 100644 --- a/src/python_testing/TC_DGWIFI_2_1.py +++ b/src/python_testing/TC_DGWIFI_2_1.py @@ -131,20 +131,17 @@ async def test_TC_DGWIFI_2_1(self): # If not NULL, we expect an integer in the SecurityType enum range. # Just do a minimal check here; you can refine or extend based on the spec. if security_type is not NullValue: - security_type_value = security_type.Value - matter_asserts.assert_valid_uint8(security_type_value, "SecurityType") + matter_asserts.assert_valid_uint8(security_type, "SecurityType") # Check if the security_type is a valid SecurityTypeEnum member - self.assert_true( - security_type_value in [item.value for item in Clusters.Objects.WiFiNetworkDiagnostics.Enums.SecurityTypeEnum], - f"SecurityType {security_type_value} is not a valid SecurityTypeEnum value" - ) + matter_asserts.assert_valid_enum(security_type, "SecurityType", + Clusters.Objects.WiFiNetworkDiagnostics.Enums.SecurityTypeEnum) # Additional check that it's not kUnknownEnumValue: self.assert_true( - security_type_value != Clusters.Objects.WiFiNetworkDiagnostics.Enums.SecurityTypeEnum.kUnknownEnumValue.value, + security_type != Clusters.Objects.WiFiNetworkDiagnostics.Enums.SecurityTypeEnum.kUnknownEnumValue, f"SecurityType should not be kUnknownEnumValue " - f"({Clusters.Objects.WiFiNetworkDiagnostics.Enums.SecurityTypeEnum.kUnknownEnumValue.value})" + f"({Clusters.Objects.WiFiNetworkDiagnostics.Enums.SecurityTypeEnum.kUnknownEnumValue})" ) # @@ -154,16 +151,15 @@ async def test_TC_DGWIFI_2_1(self): wifi_version = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.WiFiVersion) # WiFiVersion is an enum. If not configured or operational, might be NULL. if wifi_version is not NullValue: - wifi_version_value = wifi_version.Value - matter_asserts.assert_valid_uint8(wifi_version_value, "WiFiVersion") + matter_asserts.assert_valid_uint8(wifi_version, "WiFiVersion") # Check if the wifi_version is a valid WiFiVersionEnum member - self.assert_true(wifi_version_value in [item.value for item in Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum], - f"WiFiVersion {wifi_version_value} is not a valid WiFiVersionEnum value") + matter_asserts.assert_valid_enum(wifi_version, "WiFiVersion", + Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum) # Additional check that it's not kUnknownEnumValue: - self.assert_true(wifi_version_value != Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum.kUnknownEnumValue.value, - f"WiFiVersion should not be kUnknownEnumValue ({Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum.kUnknownEnumValue.value})") + self.assert_true(wifi_version != Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum.kUnknownEnumValue, + f"WiFiVersion should not be kUnknownEnumValue ({Clusters.Objects.WiFiNetworkDiagnostics.Enums.WiFiVersionEnum.kUnknownEnumValue})") # # STEP 5: TH reads ChannelNumber attribute @@ -172,7 +168,7 @@ async def test_TC_DGWIFI_2_1(self): channel_number = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.ChannelNumber) # If not operational, might be NULL. Else we expect an unsigned integer channel. if channel_number is not NullValue: - matter_asserts.assert_valid_uint16(channel_number.Value, "ChannelNumber") + matter_asserts.assert_valid_uint16(channel_number, "ChannelNumber") # # STEP 6: TH reads RSSI attribute @@ -181,8 +177,7 @@ async def test_TC_DGWIFI_2_1(self): rssi = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.Rssi) # RSSI is typically a signed integer (dB). If not operational, might be NULL. if rssi is not NullValue: - rssi_value = rssi.Value - asserts.assert_true(isinstance(rssi_value, int) and -120 <= rssi_value <= 0, + asserts.assert_true(isinstance(rssi, int) and -120 <= rssi <= 0, "rssi_value is not within valid range.") # @@ -196,7 +191,7 @@ async def test_TC_DGWIFI_2_1(self): "BeaconLostCount must be of type 'Nullable' when not None.") if beacon_lost_count is not NullValue: - matter_asserts.assert_valid_uint32(beacon_lost_count.Value, "BeaconLostCount") + matter_asserts.assert_valid_uint32(beacon_lost_count, "BeaconLostCount") # # STEP 8: TH reads BeaconRxCount attribute @@ -204,11 +199,8 @@ async def test_TC_DGWIFI_2_1(self): self.step(8) beacon_rx_count = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.BeaconRxCount) if beacon_rx_count is not None: - asserts.assert_true(isinstance(beacon_rx_count, Nullable), - "BeaconRxCount must be of type 'Nullable' when not None.") - if beacon_rx_count is not NullValue: - matter_asserts.assert_valid_uint32(beacon_rx_count.Value, "BeaconRxCount") + matter_asserts.assert_valid_uint32(beacon_rx_count, "BeaconRxCount") # # STEP 9: TH reads PacketMulticastRxCount attribute @@ -216,11 +208,8 @@ async def test_TC_DGWIFI_2_1(self): self.step(9) pkt_multi_rx = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.PacketMulticastRxCount) if pkt_multi_rx is not None: - asserts.assert_true(isinstance(pkt_multi_rx, Nullable), - "PacketMulticastRxCount must be of type 'Nullable' when not None.") - if pkt_multi_rx is not NullValue: - matter_asserts.assert_valid_uint32(pkt_multi_rx.Value, "PacketMulticastRxCount") + matter_asserts.assert_valid_uint32(pkt_multi_rx, "PacketMulticastRxCount") # # STEP 10: TH reads PacketMulticastTxCount attribute @@ -228,11 +217,8 @@ async def test_TC_DGWIFI_2_1(self): self.step(10) pkt_multi_tx = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.PacketMulticastTxCount) if pkt_multi_tx is not None: - asserts.assert_true(isinstance(pkt_multi_tx, Nullable), - "PacketMulticastTxCount must be of type 'Nullable' when not None.") - if pkt_multi_tx is not NullValue: - matter_asserts.assert_valid_uint32(pkt_multi_tx.Value, "PacketMulticastTxCount") + matter_asserts.assert_valid_uint32(pkt_multi_tx, "PacketMulticastTxCount") # # STEP 11: TH reads PacketUnicastRxCount attribute @@ -240,11 +226,8 @@ async def test_TC_DGWIFI_2_1(self): self.step(11) pkt_uni_rx = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.PacketUnicastRxCount) if pkt_uni_rx is not None: - asserts.assert_true(isinstance(pkt_uni_rx, Nullable), - "PacketUnicastRxCount must be of type 'Nullable' when not None.") - if pkt_uni_rx is not NullValue: - matter_asserts.assert_valid_uint32(pkt_uni_rx.Value, "PacketUnicastRxCount") + matter_asserts.assert_valid_uint32(pkt_uni_rx, "PacketUnicastRxCount") # # STEP 12: TH reads PacketUnicastTxCount attribute @@ -252,11 +235,8 @@ async def test_TC_DGWIFI_2_1(self): self.step(12) pkt_uni_tx = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.PacketUnicastTxCount) if pkt_uni_tx is not None: - asserts.assert_true(isinstance(pkt_uni_tx, Nullable), - "PacketUnicastTxCount must be of type 'Nullable' when not None.") - if pkt_uni_tx is not NullValue: - matter_asserts.assert_valid_uint32(pkt_uni_tx.Value, "PacketUnicastTxCount") + matter_asserts.assert_valid_uint32(pkt_uni_tx, "PacketUnicastTxCount") # # STEP 13: TH reads CurrentMaxRate attribute @@ -265,11 +245,8 @@ async def test_TC_DGWIFI_2_1(self): current_max_rate = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.CurrentMaxRate) # According to the spec, this is bytes per second (uint). if current_max_rate is not None: - asserts.assert_true(isinstance(current_max_rate, Nullable), - "CurrentMaxRate must be of type 'Nullable' when not None.") - if current_max_rate is not NullValue: - matter_asserts.assert_valid_uint64(current_max_rate.Value, "CurrentMaxRate") + matter_asserts.assert_valid_uint64(current_max_rate, "CurrentMaxRate") # # STEP 14: TH reads OverrunCount attribute @@ -278,11 +255,8 @@ async def test_TC_DGWIFI_2_1(self): overrun_count = await self.read_dgwifi_attribute_expect_success(endpoint=endpoint, attribute=attributes.OverrunCount) # This is a uint and may reset to 0 after node reboot. if overrun_count is not None: - asserts.assert_true(isinstance(overrun_count, Nullable), - "OverrunCount must be of type 'Nullable' when not None.") - if overrun_count is not NullValue: - matter_asserts.assert_valid_uint64(overrun_count.Value, "OverrunCount") + matter_asserts.assert_valid_uint64(overrun_count, "OverrunCount") if __name__ == "__main__": diff --git a/src/python_testing/TC_DGWIFI_2_3.py b/src/python_testing/TC_DGWIFI_2_3.py index c9fe7131f16593..06502e158ca9bd 100644 --- a/src/python_testing/TC_DGWIFI_2_3.py +++ b/src/python_testing/TC_DGWIFI_2_3.py @@ -33,7 +33,7 @@ # import chip.clusters as Clusters -from chip.clusters.Types import Nullable, NullValue +from chip.clusters.Types import NullValue from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main from mobly import asserts @@ -60,10 +60,9 @@ async def read_attribute_and_validate(self, endpoint, attribute, validation_func value = await self.read_single_attribute_check_success(endpoint=endpoint, cluster=Clusters.Objects.WiFiNetworkDiagnostics, attribute=attribute) if value is None: return - asserts.assert_true(isinstance(value, Nullable), f"{field_name} must be of type 'Nullable' when not None.") if value == NullValue: return - asserts.assert_true(validation_func(value.Value), f"{field_name} has an invalid value: {value.Value}") + asserts.assert_true(validation_func(value), f"{field_name} has an invalid value: {value}") def desc_TC_DGWIFI_2_3(self) -> str: """Returns a description of this test.""" From f3202b1ecaa5983377916bf8c1f4dd7404adea0d Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Fri, 24 Jan 2025 14:03:52 +0100 Subject: [PATCH 25/40] Move MockTestRunner to chip testing package (#37170) * Move MockTestRunner to chip testing package * Fix script dir path * Remove unused import --- .../matter_testing_infrastructure/BUILD.gn | 1 + .../chip/testing/runner.py} | 19 +++++++++---------- .../test_testing/TestDecorators.py | 6 ++++-- .../test_testing/common_icdm_data.py | 7 ++++--- .../test_testing/test_IDM_10_4.py | 12 +++++++----- .../test_testing/test_TC_CCNTL_2_2.py | 9 +++++---- .../test_testing/test_TC_DGGEN_3_2.py | 6 ++++-- .../test_testing/test_TC_MCORE_FS_1_1.py | 9 +++++---- .../test_testing/test_TC_SC_7_1.py | 6 ++++-- .../test_testing/test_TC_TMP_2_1.py | 6 ++++-- 10 files changed, 47 insertions(+), 34 deletions(-) rename src/python_testing/{test_testing/MockTestRunner.py => matter_testing_infrastructure/chip/testing/runner.py} (80%) diff --git a/src/python_testing/matter_testing_infrastructure/BUILD.gn b/src/python_testing/matter_testing_infrastructure/BUILD.gn index 925ad186e5ff5b..28269a3df1fbed 100644 --- a/src/python_testing/matter_testing_infrastructure/BUILD.gn +++ b/src/python_testing/matter_testing_infrastructure/BUILD.gn @@ -43,6 +43,7 @@ pw_python_package("chip-testing-module") { "chip/testing/matter_testing.py", "chip/testing/metadata.py", "chip/testing/pics.py", + "chip/testing/runner.py", "chip/testing/spec_parsing.py", "chip/testing/taglist_and_topology_test.py", "chip/testing/tasks.py", diff --git a/src/python_testing/test_testing/MockTestRunner.py b/src/python_testing/matter_testing_infrastructure/chip/testing/runner.py similarity index 80% rename from src/python_testing/test_testing/MockTestRunner.py rename to src/python_testing/matter_testing_infrastructure/chip/testing/runner.py index 85d3e613d505fd..ea060074662b5c 100644 --- a/src/python_testing/test_testing/MockTestRunner.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/runner.py @@ -17,7 +17,6 @@ import asyncio import importlib -import os import sys from pathlib import Path from unittest.mock import MagicMock @@ -33,11 +32,12 @@ async def __call__(self, *args, **kwargs): class MockTestRunner(): - def __init__(self, filename: str, classname: str, test: str, endpoint: int = None, pics: dict[str, bool] = None, paa_trust_store_path=None): + def __init__(self, abs_filename: str, classname: str, test: str, endpoint: int = None, + pics: dict[str, bool] = None, paa_trust_store_path=None): self.kvs_storage = 'kvs_admin.json' self.config = MatterTestConfig(endpoint=endpoint, paa_trust_store_path=paa_trust_store_path, pics=pics, storage_path=self.kvs_storage) - self.set_test(filename, classname, test) + self.set_test(abs_filename, classname, test) self.set_test_config(self.config) @@ -48,17 +48,16 @@ def __init__(self, filename: str, classname: str, test: str, endpoint: int = Non catTags=self.config.controller_cat_tags ) - def set_test(self, filename: str, classname: str, test: str): + def set_test(self, abs_filename: str, classname: str, test: str): self.test = test self.config.tests = [self.test] - module_name = Path(os.path.basename(filename)).stem - try: - module = importlib.import_module(module_name) + filename_path = Path(abs_filename) + module = importlib.import_module(filename_path.stem) except ModuleNotFoundError: - sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) - module = importlib.import_module(module_name) + sys.path.append(str(filename_path.parent.resolve())) + module = importlib.import_module(filename_path.stem) self.test_class = getattr(module, classname) @@ -72,7 +71,7 @@ def set_test_config(self, test_config: MatterTestConfig = MatterTestConfig()): def Shutdown(self): self.stack.Shutdown() - def run_test_with_mock_read(self, read_cache: Attribute.AsyncReadTransaction.ReadResponse, hooks=None): + def run_test_with_mock_read(self, read_cache: Attribute.AsyncReadTransaction.ReadResponse, hooks=None): self.default_controller.Read = AsyncMock(return_value=read_cache) # This doesn't need to do anything since we are overriding the read anyway self.default_controller.FindOrEstablishPASESession = AsyncMock(return_value=None) diff --git a/src/python_testing/test_testing/TestDecorators.py b/src/python_testing/test_testing/TestDecorators.py index 4d4b268ee91dfa..c2d754580c1ced 100644 --- a/src/python_testing/test_testing/TestDecorators.py +++ b/src/python_testing/test_testing/TestDecorators.py @@ -26,14 +26,15 @@ # You will get step_* calls as appropriate in between the test_start and test_stop calls if the test is not skipped. import sys +from pathlib import Path from typing import Optional import chip.clusters as Clusters from chip.clusters import Attribute from chip.testing.matter_testing import (MatterBaseTest, MatterTestConfig, async_test_body, has_attribute, has_cluster, has_feature, run_if_endpoint_matches, run_on_singleton_matching_endpoint, should_run_test_on_endpoint) +from chip.testing.runner import MockTestRunner from mobly import asserts -from MockTestRunner import MockTestRunner def get_clusters(endpoints: list[int]) -> Attribute.AsyncReadTransaction.ReadResponse: @@ -216,7 +217,8 @@ async def test_no_run_on_singleton_matching_endpoint(self): def main(): failures = [] hooks = DecoratorTestRunnerHooks() - test_runner = MockTestRunner('TestDecorators.py', 'TestDecorators', 'test_checkers') + test_runner = MockTestRunner(Path(__file__).parent / 'TestDecorators.py', + 'TestDecorators', 'test_checkers') read_resp = get_clusters([0, 1]) ok = test_runner.run_test_with_mock_read(read_resp, hooks) if not ok: diff --git a/src/python_testing/test_testing/common_icdm_data.py b/src/python_testing/test_testing/common_icdm_data.py index aa2fb235e12371..802d1240da48a7 100644 --- a/src/python_testing/test_testing/common_icdm_data.py +++ b/src/python_testing/test_testing/common_icdm_data.py @@ -18,10 +18,11 @@ import string from dataclasses import dataclass +from pathlib import Path import chip.clusters as Clusters from chip.clusters import Attribute -from MockTestRunner import MockTestRunner +from chip.testing.runner import MockTestRunner c = Clusters.IcdManagement attr = c.Attributes @@ -54,8 +55,8 @@ def test_spec_to_attribute_cache(test_icdm: ICDMData) -> Attribute.AsyncReadTran def run_tests(pics, label, test_cases, test_name): - test_runner = MockTestRunner( - label, label, test_name, 0, pics) + test_runner = MockTestRunner(Path(__file__).parent / f"../{label}.py", + label, test_name, 0, pics) failures = [] for idx, t in enumerate(test_cases): ok = test_runner.run_test_with_mock_read( diff --git a/src/python_testing/test_testing/test_IDM_10_4.py b/src/python_testing/test_testing/test_IDM_10_4.py index 8a30609e94e2cf..f7e93e9f47ea33 100644 --- a/src/python_testing/test_testing/test_IDM_10_4.py +++ b/src/python_testing/test_testing/test_IDM_10_4.py @@ -16,13 +16,13 @@ # limitations under the License. # -import os import sys +from pathlib import Path import chip.clusters as Clusters from chip.clusters import Attribute from chip.testing.pics import parse_pics_xml -from MockTestRunner import MockTestRunner +from chip.testing.runner import MockTestRunner # Reachable attribute is off in the pics file # MaxPathsPerInvoke is not include in the pics file @@ -80,10 +80,12 @@ def create_read(include_reachable: bool = False, include_max_paths: bool = False def main(): # TODO: add the same test for commands and features - script_dir = os.path.dirname(os.path.realpath(__file__)) - with open(f'{script_dir}/example_pics_xml_basic_info.xml') as f: + + script_dir = Path(__file__).resolve().parent + with open(script_dir / 'example_pics_xml_basic_info.xml') as f: pics = parse_pics_xml(f.read()) - test_runner = MockTestRunner('TC_pics_checker.py', 'TC_PICS_Checker', 'test_TC_IDM_10_4', 0, pics) + test_runner = MockTestRunner(script_dir / '../TC_pics_checker.py', + 'TC_PICS_Checker', 'test_TC_IDM_10_4', 0, pics) failures = [] # Success, include vendor ID, which IS in the pics file, and neither of the incorrect ones diff --git a/src/python_testing/test_testing/test_TC_CCNTL_2_2.py b/src/python_testing/test_testing/test_TC_CCNTL_2_2.py index 7fd7390ab6f411..7162bca33f0398 100644 --- a/src/python_testing/test_testing/test_TC_CCNTL_2_2.py +++ b/src/python_testing/test_testing/test_TC_CCNTL_2_2.py @@ -19,16 +19,16 @@ import asyncio import base64 import os -import pathlib import sys import typing +from pathlib import Path import chip.clusters as Clusters import click from chip import ChipDeviceCtrl from chip.clusters import Attribute from chip.interaction_model import InteractionModelError, Status -from MockTestRunner import AsyncMock, MockTestRunner +from chip.testing.runner import AsyncMock, MockTestRunner try: from chip.testing.matter_testing import MatterTestConfig, get_default_paa_trust_store, run_tests_no_exit @@ -175,13 +175,14 @@ def run_test_with_mock(self, dynamic_invoke_return: typing.Callable, dynamic_eve @click.command() @click.argument('th_server_app', type=click.Path(exists=True)) def main(th_server_app: str): - root = os.path.abspath(os.path.join(pathlib.Path(__file__).resolve().parent, '..', '..', '..')) + root = os.path.abspath(os.path.join(Path(__file__).resolve().parent, '..', '..', '..')) print(f'root = {root}') paa_path = get_default_paa_trust_store(root) print(f'paa = {paa_path}') pics = {"PICS_SDK_CI_ONLY": True} - test_runner = MyMock('TC_CCTRL_2_2', 'TC_CCTRL_2_2', 'test_TC_CCTRL_2_2', paa_trust_store_path=paa_path, pics=pics) + test_runner = MyMock(Path(__file__).parent / '../TC_CCTRL_2_2.py', + 'TC_CCTRL_2_2', 'test_TC_CCTRL_2_2', paa_trust_store_path=paa_path, pics=pics) config = MatterTestConfig() config.global_test_params = {'th_server_app_path': th_server_app} test_runner.set_test_config(config) diff --git a/src/python_testing/test_testing/test_TC_DGGEN_3_2.py b/src/python_testing/test_testing/test_TC_DGGEN_3_2.py index 34b80514035945..b35480cf943f8d 100644 --- a/src/python_testing/test_testing/test_TC_DGGEN_3_2.py +++ b/src/python_testing/test_testing/test_TC_DGGEN_3_2.py @@ -18,10 +18,11 @@ import sys from dataclasses import dataclass +from pathlib import Path import chip.clusters as Clusters from chip.clusters import Attribute -from MockTestRunner import MockTestRunner +from chip.testing.runner import MockTestRunner @dataclass @@ -51,7 +52,8 @@ def test_spec_to_attribute_cache(test_spec: TestSpec) -> Attribute.AsyncReadTran def main(): - test_runner = MockTestRunner('TC_DGGEN_3_2', 'TC_DGGEN_3_2', 'test_TC_DGGEN_3_2', 0) + test_runner = MockTestRunner(Path(__file__).parent / '../TC_DGGEN_3_2.py', + 'TC_DGGEN_3_2', 'test_TC_DGGEN_3_2', 0) failures = [] for idx, t in enumerate(TEST_CASES): ok = test_runner.run_test_with_mock_read(test_spec_to_attribute_cache(t)) == t.expect_pass diff --git a/src/python_testing/test_testing/test_TC_MCORE_FS_1_1.py b/src/python_testing/test_testing/test_TC_MCORE_FS_1_1.py index 0cf6b033b2f69f..225617cca733c0 100644 --- a/src/python_testing/test_testing/test_TC_MCORE_FS_1_1.py +++ b/src/python_testing/test_testing/test_TC_MCORE_FS_1_1.py @@ -19,16 +19,16 @@ import asyncio import base64 import os -import pathlib import sys import typing +from pathlib import Path import chip.clusters as Clusters import click from chip import ChipDeviceCtrl from chip.clusters import Attribute from chip.interaction_model import InteractionModelError, Status -from MockTestRunner import AsyncMock, MockTestRunner +from chip.testing.runner import AsyncMock, MockTestRunner try: from chip.testing.matter_testing import MatterTestConfig, get_default_paa_trust_store, run_tests_no_exit @@ -146,13 +146,14 @@ def run_test_with_mock(self, dynamic_invoke_return: typing.Callable, dynamic_eve @click.command() @click.argument('th_server_app', type=click.Path(exists=True)) def main(th_server_app: str): - root = os.path.abspath(os.path.join(pathlib.Path(__file__).resolve().parent, '..', '..', '..')) + root = os.path.abspath(os.path.join(Path(__file__).resolve().parent, '..', '..', '..')) print(f'root = {root}') paa_path = get_default_paa_trust_store(root) print(f'paa = {paa_path}') pics = {"PICS_SDK_CI_ONLY": True} - test_runner = MyMock('TC_MCORE_FS_1_1', 'TC_MCORE_FS_1_1', 'test_TC_MCORE_FS_1_1', paa_trust_store_path=paa_path, pics=pics) + test_runner = MyMock(Path(__file__).parent / '../TC_MCORE_FS_1_1.py', + 'TC_MCORE_FS_1_1', 'test_TC_MCORE_FS_1_1', paa_trust_store_path=paa_path, pics=pics) config = MatterTestConfig() config.user_params = {'th_server_app_path': th_server_app} test_runner.set_test_config(config) diff --git a/src/python_testing/test_testing/test_TC_SC_7_1.py b/src/python_testing/test_testing/test_TC_SC_7_1.py index 96dced72f952af..5f82a67598750b 100644 --- a/src/python_testing/test_testing/test_TC_SC_7_1.py +++ b/src/python_testing/test_testing/test_TC_SC_7_1.py @@ -17,12 +17,13 @@ # import sys +from pathlib import Path from random import randbytes import chip.clusters as Clusters from chip.clusters import Attribute from chip.testing.matter_testing import MatterTestConfig -from MockTestRunner import MockTestRunner +from chip.testing.runner import MockTestRunner def read_trusted_root(filled: bool) -> Attribute.AsyncReadTransaction.ReadResponse: @@ -43,7 +44,8 @@ def main(): manual_3333_20202021 = '31693312339' manual_2222_20202024 = '20055212333' - test_runner = MockTestRunner('TC_SC_7_1', 'TC_SC_7_1', 'test_TC_SC_7_1', 0) + test_runner = MockTestRunner(Path(__file__).parent / '../TC_SC_7_1.py', + 'TC_SC_7_1', 'test_TC_SC_7_1', 0) failures = [] # Tests with no code specified should fail diff --git a/src/python_testing/test_testing/test_TC_TMP_2_1.py b/src/python_testing/test_testing/test_TC_TMP_2_1.py index fe888a4896cb28..135cf7b918641d 100644 --- a/src/python_testing/test_testing/test_TC_TMP_2_1.py +++ b/src/python_testing/test_testing/test_TC_TMP_2_1.py @@ -19,11 +19,12 @@ import sys import typing from dataclasses import dataclass +from pathlib import Path import chip.clusters as Clusters from chip.clusters import Attribute from chip.clusters.Types import NullValue -from MockTestRunner import MockTestRunner +from chip.testing.runner import MockTestRunner @dataclass @@ -160,7 +161,8 @@ def test_spec_to_attribute_cache(test_spec: TestSpec) -> Attribute.AsyncReadTran def main(): - test_runner = MockTestRunner('TC_TMP_2_1', 'TC_TMP_2_1', 'test_TC_TMP_2_1', 1) + test_runner = MockTestRunner(Path(__file__).parent / '../TC_TMP_2_1.py', + 'TC_TMP_2_1', 'test_TC_TMP_2_1', 1) failures = [] for idx, t in enumerate(TEST_CASES): ok = test_runner.run_test_with_mock_read(test_spec_to_attribute_cache(t)) == t.expect_pass From 14ac7a69cb16cd45adac48959c253ac4691d7ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Fri, 24 Jan 2025 15:39:08 +0100 Subject: [PATCH 26/40] Update README.md (#37176) Fix broken link to test scripts --- examples/energy-management-app/linux/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/energy-management-app/linux/README.md b/examples/energy-management-app/linux/README.md index 9bb1cd3820f0a0..37a4be4e7c0e2b 100644 --- a/examples/energy-management-app/linux/README.md +++ b/examples/energy-management-app/linux/README.md @@ -156,7 +156,7 @@ CHIP-REPL is slightly easier to interact with when dealing with some of the complex structures. There are several test scripts provided for EVSE (in -[src/python_testing](src/python_testing)): +[src/python_testing](/src/python_testing)): - `TC_EEVSE_2_2`: This validates the primary functionality - `TC_EEVSE_2_3`: This validates Get/Set/Clear target commands From dca110f7d0f157a6a82a33ed2df33d541449b374 Mon Sep 17 00:00:00 2001 From: sarthak shaha Date: Fri, 24 Jan 2025 15:43:59 -0500 Subject: [PATCH 27/40] [Silabs][Docker] Silabs docker update for MGM26 (#37190) * Docker updates for MG26 This reverts commit cb7b6665297bd8732dcad29b38921078f5e1862e. * typo fix * added versions --- integrations/docker/images/base/chip-build/version | 2 +- .../docker/images/stage-2/chip-build-efr32/Dockerfile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/integrations/docker/images/base/chip-build/version b/integrations/docker/images/base/chip-build/version index ad439b9fc61f07..84408250977275 100644 --- a/integrations/docker/images/base/chip-build/version +++ b/integrations/docker/images/base/chip-build/version @@ -1 +1 @@ -100 : [linux] Added libpcsclite-dev package for NFC Commissioning on Linux platforms. +101: [Silabs] Update Silabs docker to support MG26 Modules. diff --git a/integrations/docker/images/stage-2/chip-build-efr32/Dockerfile b/integrations/docker/images/stage-2/chip-build-efr32/Dockerfile index eb67c80ff9a080..66a036a443a223 100644 --- a/integrations/docker/images/stage-2/chip-build-efr32/Dockerfile +++ b/integrations/docker/images/stage-2/chip-build-efr32/Dockerfile @@ -25,8 +25,8 @@ RUN wget https://github.com/SiliconLabs/simplicity_sdk/releases/download/v2024.1 && find /tmp/simplicity_sdk/protocol/openthread -name "*efr32mg21*" -delete \ && find /tmp/simplicity_sdk \( -name "libsl_platform_ftd_efr32mg2*" -o -name "libsl_ot_stack_mtd_efr32mg2*" \) -type f -delete \ && find /tmp/simplicity_sdk/hardware/board/config -mindepth 1 -maxdepth 1 -type d ! \( -name '*brd4186c*' -o -name '*brd4187c*' -o -name '*brd4186a*' -o -name '*brd4187a*' -o -name '*brd2601b*' -o -name '*brd2703a*' -o -name '*brd2704a*' -o -name '*component*' \ - -o -name '*brd4316a*' -o -name '*brd4317a*' -o -name '*brd4318a*' -o -name '*brd4319a*' -o -name '*brd4116a*' -o -name '*brd4117a*' -o -name '*brd4118a*' -o -name '*brd2608a*' \) -exec rm -rf {} + \ - && find /tmp/simplicity_sdk/platform/Device/SiliconLabs -mindepth 1 -maxdepth 1 -type d ! \( -name 'EFR32MG24' -o -name 'EFR32MG26' -o -name 'MGM24' \) -exec rm -rf {} + \ + -o -name '*brd4316a*' -o -name '*brd4317a*' -o -name '*brd4318a*' -o -name '*brd4319a*' -o -name '*brd4116a*' -o -name '*brd4117a*' -o -name '*brd4118a*' -o -name '*brd2608a*' -o -name '*brd4350a*' -o -name '*brd4351a*' -o -name '*brd2709a*' \) -exec rm -rf {} + \ + && find /tmp/simplicity_sdk/platform/Device/SiliconLabs -mindepth 1 -maxdepth 1 -type d ! \( -name 'EFR32MG24' -o -name 'EFR32MG26' -o -name 'MGM24' -o -name 'MGM26' \) -exec rm -rf {} + \ && : # last line # Clone WiSeConnect Wi-Fi and Bluetooth Software 2.10.3 (b6d6cb5) From 8a916c120e89663f568a72203c16769c2dea0b26 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Fri, 24 Jan 2025 15:52:00 -0500 Subject: [PATCH 28/40] Fix up docker: fix nuttx mirror to one with a good certificate, update version to make sense (#37196) Co-authored-by: Andrei Litvin --- integrations/docker/images/base/chip-build/version | 2 +- integrations/docker/images/stage-2/chip-build-nuttx/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/integrations/docker/images/base/chip-build/version b/integrations/docker/images/base/chip-build/version index 84408250977275..60379853bb3fdc 100644 --- a/integrations/docker/images/base/chip-build/version +++ b/integrations/docker/images/base/chip-build/version @@ -1 +1 @@ -101: [Silabs] Update Silabs docker to support MG26 Modules. +101 : [Silabs] Update Silabs docker to support MG26 Modules. diff --git a/integrations/docker/images/stage-2/chip-build-nuttx/Dockerfile b/integrations/docker/images/stage-2/chip-build-nuttx/Dockerfile index fdc28b4eaff6a8..c8d6a2177dc438 100644 --- a/integrations/docker/images/stage-2/chip-build-nuttx/Dockerfile +++ b/integrations/docker/images/stage-2/chip-build-nuttx/Dockerfile @@ -14,7 +14,7 @@ RUN set -x \ # Download and build g++-13 RUN set -x \ && ! test -d /opt/nuttx/gcc-13 \ - && wget -P gcc_build https://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-13.1.0/gcc-13.1.0.tar.gz \ + && wget -P gcc_build https://mirrorservice.org/sites/sourceware.org/pub/gcc/releases/gcc-13.1.0/gcc-13.1.0.tar.gz \ && cd gcc_build \ && tar xzf gcc-13.1.0.tar.gz \ && cd gcc-13.1.0 \ From 281adfdee7be66b865022c9e5adb12a535d05ed3 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 24 Jan 2025 16:04:25 -0500 Subject: [PATCH 29/40] Add a method to Darwin SetupPayload to test whether a passcode is valid. (#37193) --- src/darwin/Framework/CHIP/MTRSetupPayload.h | 8 ++++- src/darwin/Framework/CHIP/MTRSetupPayload.mm | 11 ++++++ .../CHIPTests/MTRSetupPayloadTests.m | 35 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/darwin/Framework/CHIP/MTRSetupPayload.h b/src/darwin/Framework/CHIP/MTRSetupPayload.h index d1cd5550bcf800..99a9bb844a7302 100644 --- a/src/darwin/Framework/CHIP/MTRSetupPayload.h +++ b/src/darwin/Framework/CHIP/MTRSetupPayload.h @@ -175,7 +175,7 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) /** * Generate a random Matter-valid setup PIN. */ -+ (NSUInteger)generateRandomPIN; ++ (NSUInteger)generateRandomPIN MTR_NEWLY_DEPRECATED("Please use generateRandomSetupPasscode"); /** * Generate a random Matter-valid setup passcode. @@ -214,6 +214,12 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) */ - (NSString * _Nullable)qrCodeString MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)); +/** + * Check whether the provided setup passcode (represented as an unsigned + * integer) is a valid setup passcode. + */ ++ (BOOL)isValidSetupPasscode:(NSNumber *)setupPasscode MTR_NEWLY_AVAILABLE; + @end MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)) diff --git a/src/darwin/Framework/CHIP/MTRSetupPayload.mm b/src/darwin/Framework/CHIP/MTRSetupPayload.mm index c4694884ea829d..f85d785071176a 100644 --- a/src/darwin/Framework/CHIP/MTRSetupPayload.mm +++ b/src/darwin/Framework/CHIP/MTRSetupPayload.mm @@ -476,6 +476,17 @@ - (nullable NSString *)qrCodeString return [self qrCodeStringSkippingValidation:NO]; } ++ (BOOL)isValidSetupPasscode:(NSNumber *)setupPasscode +{ + using namespace chip; + + uint64_t passCode = setupPasscode.unsignedLongLongValue; + if (!CanCastTo(passCode)) { + return NO; + } + return SetupPayload::IsValidSetupPIN(static_cast(passCode)); +} + - (nullable NSString *)qrCodeStringSkippingValidation:(BOOL)allowInvalid { chip::QRCodeSetupPayloadGenerator generator(_payload); diff --git a/src/darwin/Framework/CHIPTests/MTRSetupPayloadTests.m b/src/darwin/Framework/CHIPTests/MTRSetupPayloadTests.m index 6f53305f943a69..df99c3b7cda8c1 100644 --- a/src/darwin/Framework/CHIPTests/MTRSetupPayloadTests.m +++ b/src/darwin/Framework/CHIPTests/MTRSetupPayloadTests.m @@ -439,4 +439,39 @@ - (void)testDescriptionShowsUnknownDiscoveryMethods XCTAssertNotEqualObjects(a.description, b.description); } +- (uint32)generateRepeatedDigitPasscode:(uint8_t)digit +{ + // "digit" is expected to be a single digit. Generates a number that has + // that digit repeated 8 times. + uint32_t passcode = 0; + for (int i = 0; i < 8; ++i) { + passcode = passcode * 10 + digit; + } + return passcode; +} + +- (void)testValidSetupPasscode +{ + // First, check the repeated-digit cases. + for (uint8_t digit = 0; digit <= 9; ++digit) { + XCTAssertFalse([MTRSetupPayload isValidSetupPasscode:@([self generateRepeatedDigitPasscode:digit])]); + } + + // Then the sequential special cases. + XCTAssertFalse([MTRSetupPayload isValidSetupPasscode:@(12345678)]); + XCTAssertFalse([MTRSetupPayload isValidSetupPasscode:@(87654321)]); + + // Then the "too big" cases: + XCTAssertFalse([MTRSetupPayload isValidSetupPasscode:@(100000000)]); + XCTAssertFalse([MTRSetupPayload isValidSetupPasscode:@(1lu << 27)]); + XCTAssertFalse([MTRSetupPayload isValidSetupPasscode:@((1llu << 32) + 1)]); + + // Now some tests for known-valid passcodes: + XCTAssertTrue([MTRSetupPayload isValidSetupPasscode:@(1)]); + XCTAssertTrue([MTRSetupPayload isValidSetupPasscode:@(78654321)]); + + // And we should only generate valid ones. + XCTAssertTrue([MTRSetupPayload isValidSetupPasscode:[MTRSetupPayload generateRandomSetupPasscode]]); +} + @end From c7187505c5a6f8d961baf3eb8273ee81e0e322c3 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Fri, 24 Jan 2025 16:36:39 -0500 Subject: [PATCH 30/40] Re-use `chip::app::DataModel::DeviceTypeEntry` as `EmberAfDeviceType` (#37143) * Start splitting metadata types - just rename types and dependencies for now * Fix/update some includes to make things compile - at least tests compile * Restyle * Restyled by gn * Fix rpc Descript variable name * Add header to gn * Fix header comment / license (bad copy & paste) * Fix darwin * Fix another reference to deviceId (this time in android code) * Fix merge issues * Add missing file * Take metadata types out of the data-model-provider and keep it in one target only * Update src/darwin/Framework/CHIP/ServerEndpoint/MTRServerEndpoint.mm Co-authored-by: Boris Zbarsky --------- Co-authored-by: Andrei Litvin Co-authored-by: Restyled.io Co-authored-by: Boris Zbarsky --- .../common/pigweed/rpc_services/Descriptor.h | 2 +- .../android/java/DeviceApp-JNI.cpp | 2 +- src/app/data-model-provider/BUILD.gn | 16 +++- src/app/data-model-provider/MetadataLookup.h | 1 + src/app/data-model-provider/MetadataTypes.h | 68 -------------- src/app/data-model-provider/Provider.h | 2 +- ...dataTypes.cpp => ProviderMetadataTree.cpp} | 2 +- .../ProviderMetadataTree.h | 94 +++++++++++++++++++ src/app/util/BUILD.gn | 1 + src/app/util/af-types.h | 11 +-- .../CHIP/ServerEndpoint/MTRServerEndpoint.mm | 8 +- .../codegen/CodegenDataModelProvider.cpp | 23 +---- 12 files changed, 121 insertions(+), 109 deletions(-) rename src/app/data-model-provider/{MetadataTypes.cpp => ProviderMetadataTree.cpp} (96%) create mode 100644 src/app/data-model-provider/ProviderMetadataTree.h diff --git a/examples/common/pigweed/rpc_services/Descriptor.h b/examples/common/pigweed/rpc_services/Descriptor.h index a6760cdcf61ce3..ec2e323da49879 100644 --- a/examples/common/pigweed/rpc_services/Descriptor.h +++ b/examples/common/pigweed/rpc_services/Descriptor.h @@ -52,7 +52,7 @@ class Descriptor : public pw_rpc::nanopb::Descriptor::Service // TODO: Need to update the Pigweed proto definition to actually represent this // as a list of device types. // - chip_rpc_DeviceType out{ .device_type = deviceTypeList.data()[0].deviceId }; + chip_rpc_DeviceType out{ .device_type = deviceTypeList.data()[0].deviceTypeId }; writer.Write(out); } diff --git a/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp b/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp index 4636dab286df65..22b667be4aa1f1 100644 --- a/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp +++ b/examples/virtual-device-app/android/java/DeviceApp-JNI.cpp @@ -134,7 +134,7 @@ JNI_METHOD(void, postServerInit)(JNIEnv *, jobject app, jint deviceTypeId) chip::DeviceLayer::StackLock lock; ChipLogProgress(Zcl, "DeviceAppJNI::postServerInit"); - gDeviceTypeIds[0].deviceId = static_cast(deviceTypeId); + gDeviceTypeIds[0].deviceTypeId = static_cast(deviceTypeId); emberAfSetDeviceTypeList(1, Span(gDeviceTypeIds)); } diff --git a/src/app/data-model-provider/BUILD.gn b/src/app/data-model-provider/BUILD.gn index 5804b0acf59cf5..a57e7d11fbde5d 100644 --- a/src/app/data-model-provider/BUILD.gn +++ b/src/app/data-model-provider/BUILD.gn @@ -14,6 +14,16 @@ import("//build_overrides/chip.gni") import("//build_overrides/pigweed.gni") +source_set("metadata") { + sources = [ "MetadataTypes.h" ] + + public_deps = [ + "${chip_root}/src/access:types", + "${chip_root}/src/lib/core:types", + "${chip_root}/src/lib/support", + ] +} + source_set("data-model-provider") { sources = [ "ActionContext.h", @@ -25,15 +35,15 @@ source_set("data-model-provider") { "MetadataList.h", "MetadataLookup.cpp", "MetadataLookup.h", - "MetadataTypes.cpp", - "MetadataTypes.h", "OperationTypes.h", "Provider.h", "ProviderChangeListener.h", + "ProviderMetadataTree.cpp", + "ProviderMetadataTree.h", ] public_deps = [ - "${chip_root}/src/access:types", + ":metadata", "${chip_root}/src/app:attribute-access", "${chip_root}/src/app:command-handler-interface", "${chip_root}/src/app:events", diff --git a/src/app/data-model-provider/MetadataLookup.h b/src/app/data-model-provider/MetadataLookup.h index 9c2978d71a5ae6..1d25122e7e8281 100644 --- a/src/app/data-model-provider/MetadataLookup.h +++ b/src/app/data-model-provider/MetadataLookup.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include diff --git a/src/app/data-model-provider/MetadataTypes.h b/src/app/data-model-provider/MetadataTypes.h index 5b6bccb863e660..baeb899d48968b 100644 --- a/src/app/data-model-provider/MetadataTypes.h +++ b/src/app/data-model-provider/MetadataTypes.h @@ -20,17 +20,8 @@ #include #include -#include -#include -#include -#include -#include -#include -#include #include #include -#include -#include namespace chip { namespace app { @@ -135,65 +126,6 @@ struct DeviceTypeEntry } }; -/// Provides metadata information for a data model -/// -/// The data model can be viewed as a tree of endpoint/cluster/(attribute+commands+events) -/// where each element can be iterated through independently. -/// -/// Iteration rules: -/// - Invalid paths will be returned when iteration ends (IDs will be kInvalid* and in particular -/// mEndpointId will be kInvalidEndpointId). See `::kInvalid` constants for entries and -/// can use ::IsValid() to determine if the entry is valid or not. -/// - Global Attributes are NOT returned since they are implied -/// - Any internal iteration errors are just logged (callers do not handle iteration CHIP_ERROR) -/// - Iteration order is NOT guaranteed globally. Only the following is guaranteed: -/// - Complete tree iteration (e.g. when iterating an endpoint, ALL clusters of that endpoint -/// are returned, when iterating over a cluster, all attributes/commands are iterated over) -/// - uniqueness and completeness (iterate over all possible distinct values as long as no -/// internal structural changes occur) -class ProviderMetadataTree -{ -public: - virtual ~ProviderMetadataTree() = default; - - using SemanticTag = Clusters::Descriptor::Structs::SemanticTagStruct::Type; - - virtual CHIP_ERROR Endpoints(ListBuilder & builder) = 0; - - virtual CHIP_ERROR SemanticTags(EndpointId endpointId, ListBuilder & builder) = 0; - virtual CHIP_ERROR DeviceTypes(EndpointId endpointId, ListBuilder & builder) = 0; - virtual CHIP_ERROR ClientClusters(EndpointId endpointId, ListBuilder & builder) = 0; - virtual CHIP_ERROR ServerClusters(EndpointId endpointId, ListBuilder & builder) = 0; - - virtual CHIP_ERROR Attributes(const ConcreteClusterPath & path, ListBuilder & builder) = 0; - virtual CHIP_ERROR GeneratedCommands(const ConcreteClusterPath & path, ListBuilder & builder) = 0; - virtual CHIP_ERROR AcceptedCommands(const ConcreteClusterPath & path, ListBuilder & builder) = 0; - - /// Workaround function to report attribute change. - /// - /// When this is invoked, the caller is expected to increment the cluster data version, and the attribute path - /// should be marked as `dirty` by the data model provider listener so that the reporter can notify the subscriber - /// of attribute changes. - /// This function should be invoked when attribute managed by attribute access interface is modified but not - /// through an actual Write interaction. - /// For example, if the LastNetworkingStatus attribute changes because the NetworkCommissioning driver detects a - /// network connection status change and calls SetLastNetworkingStatusValue(). The data model provider can recognize - /// this change by invoking this function at the point of change. - /// - /// This is a workaround function as we cannot notify the attribute change to the data model provider. The provider - /// should own its data and versions. - /// - /// TODO: We should remove this function when the AttributeAccessInterface/CommandHandlerInterface is able to report - /// the attribute changes. - virtual void Temporary_ReportAttributeChanged(const AttributePathParams & path) = 0; - - // "convenience" functions that just return the data and ignore the error - // This returns the builder as-is even after the error (e.g. not found would return empty data) - ReadOnlyBuffer EndpointsIgnoreError(); - ReadOnlyBuffer ServerClustersIgnoreError(EndpointId endpointId); - ReadOnlyBuffer AttributesIgnoreError(const ConcreteClusterPath & path); -}; - } // namespace DataModel } // namespace app } // namespace chip diff --git a/src/app/data-model-provider/Provider.h b/src/app/data-model-provider/Provider.h index 1d3fff75324351..13d5a4a4f55e7c 100644 --- a/src/app/data-model-provider/Provider.h +++ b/src/app/data-model-provider/Provider.h @@ -27,8 +27,8 @@ #include #include -#include #include +#include namespace chip { namespace app { diff --git a/src/app/data-model-provider/MetadataTypes.cpp b/src/app/data-model-provider/ProviderMetadataTree.cpp similarity index 96% rename from src/app/data-model-provider/MetadataTypes.cpp rename to src/app/data-model-provider/ProviderMetadataTree.cpp index 6d87d9b5ea54ac..8b6b4b6d5c6ccb 100644 --- a/src/app/data-model-provider/MetadataTypes.cpp +++ b/src/app/data-model-provider/ProviderMetadataTree.cpp @@ -15,7 +15,7 @@ * limitations under the License. */ -#include +#include #include diff --git a/src/app/data-model-provider/ProviderMetadataTree.h b/src/app/data-model-provider/ProviderMetadataTree.h new file mode 100644 index 00000000000000..cd1ff179806e3b --- /dev/null +++ b/src/app/data-model-provider/ProviderMetadataTree.h @@ -0,0 +1,94 @@ +/* + * 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. + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace DataModel { + +/// Provides metadata information for a data model +/// +/// The data model can be viewed as a tree of endpoint/cluster/(attribute+commands+events) +/// where each element can be iterated through independently. +/// +/// Iteration rules: +/// - Invalid paths will be returned when iteration ends (IDs will be kInvalid* and in particular +/// mEndpointId will be kInvalidEndpointId). See `::kInvalid` constants for entries and +/// can use ::IsValid() to determine if the entry is valid or not. +/// - Global Attributes are NOT returned since they are implied +/// - Any internal iteration errors are just logged (callers do not handle iteration CHIP_ERROR) +/// - Iteration order is NOT guaranteed globally. Only the following is guaranteed: +/// - Complete tree iteration (e.g. when iterating an endpoint, ALL clusters of that endpoint +/// are returned, when iterating over a cluster, all attributes/commands are iterated over) +/// - uniqueness and completeness (iterate over all possible distinct values as long as no +/// internal structural changes occur) +class ProviderMetadataTree +{ +public: + virtual ~ProviderMetadataTree() = default; + + using SemanticTag = Clusters::Descriptor::Structs::SemanticTagStruct::Type; + + virtual CHIP_ERROR Endpoints(ListBuilder & builder) = 0; + + virtual CHIP_ERROR SemanticTags(EndpointId endpointId, ListBuilder & builder) = 0; + virtual CHIP_ERROR DeviceTypes(EndpointId endpointId, ListBuilder & builder) = 0; + virtual CHIP_ERROR ClientClusters(EndpointId endpointId, ListBuilder & builder) = 0; + virtual CHIP_ERROR ServerClusters(EndpointId endpointId, ListBuilder & builder) = 0; + + virtual CHIP_ERROR Attributes(const ConcreteClusterPath & path, ListBuilder & builder) = 0; + virtual CHIP_ERROR GeneratedCommands(const ConcreteClusterPath & path, ListBuilder & builder) = 0; + virtual CHIP_ERROR AcceptedCommands(const ConcreteClusterPath & path, ListBuilder & builder) = 0; + + /// Workaround function to report attribute change. + /// + /// When this is invoked, the caller is expected to increment the cluster data version, and the attribute path + /// should be marked as `dirty` by the data model provider listener so that the reporter can notify the subscriber + /// of attribute changes. + /// This function should be invoked when attribute managed by attribute access interface is modified but not + /// through an actual Write interaction. + /// For example, if the LastNetworkingStatus attribute changes because the NetworkCommissioning driver detects a + /// network connection status change and calls SetLastNetworkingStatusValue(). The data model provider can recognize + /// this change by invoking this function at the point of change. + /// + /// This is a workaround function as we cannot notify the attribute change to the data model provider. The provider + /// should own its data and versions. + /// + /// TODO: We should remove this function when the AttributeAccessInterface/CommandHandlerInterface is able to report + /// the attribute changes. + virtual void Temporary_ReportAttributeChanged(const AttributePathParams & path) = 0; + + // "convenience" functions that just return the data and ignore the error + // This returns the builder as-is even after the error (e.g. not found would return empty data) + ReadOnlyBuffer EndpointsIgnoreError(); + ReadOnlyBuffer ServerClustersIgnoreError(EndpointId endpointId); + ReadOnlyBuffer AttributesIgnoreError(const ConcreteClusterPath & path); +}; + +} // namespace DataModel +} // namespace app +} // namespace chip diff --git a/src/app/util/BUILD.gn b/src/app/util/BUILD.gn index 2feae78fbfba3c..d6e63be1a8d01f 100644 --- a/src/app/util/BUILD.gn +++ b/src/app/util/BUILD.gn @@ -60,6 +60,7 @@ source_set("af-types") { "${chip_root}/src/app:paths", "${chip_root}/src/app/common:cluster-objects", "${chip_root}/src/app/data-model", + "${chip_root}/src/app/data-model-provider:metadata", "${chip_root}/src/messaging", "${chip_root}/src/protocols/interaction_model", ] diff --git a/src/app/util/af-types.h b/src/app/util/af-types.h index e3559069ed9df3..d576c3285bbf7a 100644 --- a/src/app/util/af-types.h +++ b/src/app/util/af-types.h @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -124,15 +125,7 @@ struct EmberAfCluster bool IsClient() const { return (mask & CLUSTER_MASK_CLIENT) != 0; } }; -/** - * @brief Struct that represents a logical device type consisting - * of a DeviceID and its version. - */ -typedef struct -{ - chip::DeviceTypeId deviceId; - uint8_t deviceVersion; -} EmberAfDeviceType; +using EmberAfDeviceType = chip::app::DataModel::DeviceTypeEntry; /** * @brief Struct used to find an attribute in storage. Together the elements diff --git a/src/darwin/Framework/CHIP/ServerEndpoint/MTRServerEndpoint.mm b/src/darwin/Framework/CHIP/ServerEndpoint/MTRServerEndpoint.mm index 1b0f27fbaf141e..2ea97b3d8e45b2 100644 --- a/src/darwin/Framework/CHIP/ServerEndpoint/MTRServerEndpoint.mm +++ b/src/darwin/Framework/CHIP/ServerEndpoint/MTRServerEndpoint.mm @@ -301,10 +301,10 @@ - (BOOL)finishAssociationWithController:(nullable MTRDeviceController *)controll auto * deviceType = _deviceTypes[index]; auto & matterType = _matterDeviceTypes[index]; - matterType.deviceId = static_cast(deviceType.deviceTypeID.unsignedLongLongValue); - // TODO: The spec allows 16-bit revisions, but the Ember bits only - // support 8-bit.... - matterType.deviceVersion = static_cast(deviceType.deviceTypeRevision.unsignedLongLongValue); + matterType.deviceTypeId = static_cast(deviceType.deviceTypeID.unsignedLongLongValue); + // TODO: The spec allows 16-bit revisions, but DeviceTypeEntry only + // supports 8-bit.... + matterType.deviceTypeRevision = static_cast(deviceType.deviceTypeRevision.unsignedLongLongValue); } _matterDataVersions = std::make_unique(clusterCount); diff --git a/src/data-model-providers/codegen/CodegenDataModelProvider.cpp b/src/data-model-providers/codegen/CodegenDataModelProvider.cpp index a7572fbb0322f7..a3889fb1e25ebb 100644 --- a/src/data-model-providers/codegen/CodegenDataModelProvider.cpp +++ b/src/data-model-providers/codegen/CodegenDataModelProvider.cpp @@ -118,18 +118,6 @@ DataModel::AttributeEntry AttributeEntryFrom(const ConcreteClusterPath & cluster return entry; } -// TODO: DeviceTypeEntry content is IDENTICAL to EmberAfDeviceType, so centralizing -// to a common type is probably better. Need to figure out dependencies since -// this would make ember return datamodel-provider types. -// See: https://github.com/project-chip/connectedhomeip/issues/35889 -DataModel::DeviceTypeEntry DeviceTypeEntryFromEmber(const EmberAfDeviceType & other) -{ - return DataModel::DeviceTypeEntry{ - .deviceTypeId = other.deviceId, - .deviceTypeRevision = other.deviceVersion, - }; -} - const ConcreteCommandPath kInvalidCommandPath(kInvalidEndpointId, kInvalidClusterId, kInvalidCommandId); DefaultAttributePersistenceProvider gDefaultAttributePersistence; @@ -494,16 +482,9 @@ CHIP_ERROR CodegenDataModelProvider::DeviceTypes(EndpointId endpointId, return {}; } - CHIP_ERROR err = CHIP_NO_ERROR; - Span deviceTypes = emberAfDeviceTypeListFromEndpointIndex(*endpoint_index, err); - - ReturnErrorOnFailure(builder.EnsureAppendCapacity(deviceTypes.size())); - - for (auto & entry : deviceTypes) - { - ReturnErrorOnFailure(builder.Append(DeviceTypeEntryFromEmber(entry))); - } + CHIP_ERROR err = CHIP_NO_ERROR; + builder.ReferenceExisting(emberAfDeviceTypeListFromEndpointIndex(*endpoint_index, err)); return CHIP_NO_ERROR; } From 74593dc4f30e28eec5196726fa69a18382b715ab Mon Sep 17 00:00:00 2001 From: senthilku Date: Sat, 25 Jan 2025 03:12:17 +0530 Subject: [PATCH 31/40] [Silabs] Added join callback handler to fix rejoin issue (#37145) * added join callback handler * fix restyled issue * remove reinterpret casting for scan/join failure status * removed c typecast and updated with c++ type casting --- .../silabs/wifi/SiWx/WifiInterfaceImpl.cpp | 45 ++++++++++++++++--- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/platform/silabs/wifi/SiWx/WifiInterfaceImpl.cpp b/src/platform/silabs/wifi/SiWx/WifiInterfaceImpl.cpp index 00094dbb9a93bb..9f6fcce1eff188 100644 --- a/src/platform/silabs/wifi/SiWx/WifiInterfaceImpl.cpp +++ b/src/platform/silabs/wifi/SiWx/WifiInterfaceImpl.cpp @@ -319,14 +319,17 @@ sl_status_t ScanCallback(sl_wifi_event_t event, sl_wifi_scan_result_t * scan_res sl_status_t status = SL_STATUS_OK; if (SL_WIFI_CHECK_IF_EVENT_FAILED(event)) { - ChipLogError(DeviceLayer, "Scan Netwrok Failed: 0x%lx", *reinterpret_cast(status)); + if (scan_result != nullptr) + { + status = *reinterpret_cast(scan_result); + ChipLogError(DeviceLayer, "ScanCallback: failed: 0x%lx", status); + } + #if WIFI_ENABLE_SECURITY_WPA3_TRANSITION security = SL_WIFI_WPA3; #else security = SL_WIFI_WPA_WPA2_MIXED; #endif /* WIFI_ENABLE_SECURITY_WPA3_TRANSITION */ - - status = SL_STATUS_FAIL; } else { @@ -421,6 +424,35 @@ sl_status_t SetWifiConfigurations() return status; } +/** + * @brief Callback function for the SL_WIFI_JOIN_EVENTS group + * + * This callback handler will be invoked when any event within join event group occurs, providing the event details and any + * associated data The callback doesn't get called when we join a network using the sl net APIs + * + * @note In case of failure, the 'result' parameter will be of type sl_status_t, and the 'resultLenght' parameter should be ignored + * + * @param[in] event sl_wifi_event_t that triggered the callback + * @param[in] result Pointer to the response data received + * @param[in] result_length Length of the data received in bytes + * @param[in] arg Optional user provided argument + * + * @return sl_status_t Returns the status of the operation + */ +sl_status_t JoinCallback(sl_wifi_event_t event, char * result, uint32_t resultLenght, void * arg) +{ + sl_status_t status = SL_STATUS_OK; + wfx_rsi.dev_state.Clear(WifiState::kStationConnecting); + if (SL_WIFI_CHECK_IF_EVENT_FAILED(event)) + { + status = *reinterpret_cast(result); + ChipLogError(DeviceLayer, "JoinCallback: failed: 0x%lx", status); + wfx_rsi.dev_state.Clear(WifiState::kStationConnected); + wfx_retry_connection(++wfx_rsi.join_retries); + } + + return status; +} sl_status_t JoinWifiNetwork(void) { VerifyOrReturnError(!wfx_rsi.dev_state.HasAny(WifiState::kStationConnecting, WifiState::kStationConnected), @@ -433,6 +465,9 @@ sl_status_t JoinWifiNetwork(void) status = SetWifiConfigurations(); VerifyOrReturnError(status == SL_STATUS_OK, status, ChipLogError(DeviceLayer, "Failure to set the Wifi Configurations!")); + status = sl_wifi_set_join_callback(JoinCallback, nullptr); + VerifyOrReturnError(status == SL_STATUS_OK, status); + status = sl_net_up((sl_net_interface_t) SL_NET_WIFI_CLIENT_INTERFACE, SL_NET_DEFAULT_WIFI_CLIENT_PROFILE_ID); if (status == SL_STATUS_OK || status == SL_STATUS_IN_PROGRESS) @@ -444,16 +479,12 @@ sl_status_t JoinWifiNetwork(void) // failure only happens when the firmware returns an error ChipLogError(DeviceLayer, "sl_wifi_connect failed: 0x%lx", static_cast(status)); - VerifyOrReturnError((wfx_rsi.join_retries <= MAX_JOIN_RETRIES_COUNT), status); wfx_rsi.dev_state.Clear(WifiState::kStationConnecting).Clear(WifiState::kStationConnected); ChipLogProgress(DeviceLayer, "Connection retry attempt %d", wfx_rsi.join_retries); wfx_retry_connection(++wfx_rsi.join_retries); - WifiPlatformEvent event = WifiPlatformEvent::kStationStartJoin; - PostWifiPlatformEvent(event); - return status; } From 0899eee9702afaea275bc1691510a61335d93cf1 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Fri, 24 Jan 2025 15:30:10 -0800 Subject: [PATCH 32/40] Implement python test for TC_DGTHREAD_2_2 (#37185) --- src/python_testing/TC_DGTHREAD_2_2.py | 243 ++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 src/python_testing/TC_DGTHREAD_2_2.py diff --git a/src/python_testing/TC_DGTHREAD_2_2.py b/src/python_testing/TC_DGTHREAD_2_2.py new file mode 100644 index 00000000000000..61e520e29c2ea1 --- /dev/null +++ b/src/python_testing/TC_DGTHREAD_2_2.py @@ -0,0 +1,243 @@ +# +# Copyright (c) 2025 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. +# + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${ALL_CLUSTERS_APP} +# app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# 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 +# factory-reset: true +# quiet: true +# === END CI TEST ARGUMENTS === +# + +import chip.clusters as Clusters +from chip.testing import matter_asserts +from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main + + +class TC_THREADND_2_2(MatterBaseTest): + """ + [TC-THREADND-2.2] Thread Network Diagnostics Cluster - Attribute Read Verification for Tx Attributes + + This test case verifies the behavior of the Tx-related attributes of the Thread Network Diagnostics + cluster server (Server as DUT). The test case steps are derived from the provided + test plan specification. + """ + + async def read_thread_diagnostics_attribute_expect_success(self, endpoint, attribute): + """ + Convenience method to read a single ThreadNetworkDiagnostics attribute, + ensuring success. + """ + cluster = Clusters.Objects.ThreadNetworkDiagnostics + return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attribute) + + # + # --- Test Description, PICS, and Steps --- + # + def desc_TC_THREADND_2_2(self) -> str: + return "[TC-THREADND-2.2] Thread Network Diagnostics Tx Attributes with Server as DUT" + + def pics_TC_THREADND_2_2(self) -> list[str]: + return ["THREADND.S", "THREADND.SF.MACCNT"] # PICS identifiers for the test case + + def steps_TC_THREADND_2_2(self) -> list[TestStep]: + """ + Lists the test steps from the specification in an easy-to-read format. + """ + return [ + TestStep(1, "Commission DUT to TH (already done)", is_commissioning=True), + TestStep(2, "Read TxTotalCount attribute"), + TestStep(3, "Read TxUnicastCount attribute"), + TestStep(4, "Read TxBroadcastCount attribute"), + TestStep(5, "Read TxAckRequestedCount attribute"), + TestStep(6, "Read TxAckedCount attribute"), + TestStep(7, "Read TxNoAckRequestedCount attribute"), + TestStep(8, "Read TxDataCount attribute"), + TestStep(9, "Read TxDataPollCount attribute"), + TestStep(10, "Read TxBeaconCount attribute"), + TestStep(11, "Read TxBeaconRequestCount attribute"), + TestStep(12, "Read TxOtherCount attribute"), + TestStep(13, "Read TxRetryCount attribute"), + TestStep(14, "Read TxDirectMaxRetryExpiryCount attribute"), + TestStep(15, "Read TxIndirectMaxRetryExpiryCount attribute"), + TestStep(16, "Read TxErrCcaCount attribute"), + TestStep(17, "Read TxErrAbortCount attribute"), + TestStep(18, "Read TxErrBusyChannelCount attribute"), + ] + + # + # --- Main Test Routine --- + # + @async_test_body + async def test_TC_THREADND_2_2(self): + endpoint = self.get_endpoint(default=0) + attributes = Clusters.ThreadNetworkDiagnostics.Attributes + + # + # STEP 1: Commissioning (assumed done) + # + self.step(1) + # Normally performed by harness; no explicit code needed if already commissioned. + + # + # STEP 2: Read TxTotalCount + # + self.step(2) + tx_total_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxTotalCount) + if tx_total_count is not None: + matter_asserts.assert_valid_uint32(tx_total_count, "TxTotalCount") + + # + # STEP 3: Read TxUnicastCount + # + self.step(3) + tx_unicast_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxUnicastCount) + if tx_unicast_count is not None: + matter_asserts.assert_valid_uint32(tx_unicast_count, "TxUnicastCount") + + # + # STEP 4: Read TxBroadcastCount + # + self.step(4) + tx_broadcast_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxBroadcastCount) + if tx_broadcast_count is not None: + matter_asserts.assert_valid_uint32(tx_broadcast_count, "TxBroadcastCount") + + # + # STEP 5: Read TxAckRequestedCount + # + self.step(5) + tx_ack_requested_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxAckRequestedCount) + if tx_ack_requested_count is not None: + matter_asserts.assert_valid_uint32(tx_ack_requested_count, "TxAckRequestedCount") + + # + # STEP 6: Read TxAckedCount + # + self.step(6) + tx_acked_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxAckedCount) + if tx_acked_count is not None: + matter_asserts.assert_valid_uint32(tx_acked_count, "TxAckedCount") + + # + # STEP 7: Read TxNoAckRequestedCount + # + self.step(7) + tx_no_ack_requested_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxNoAckRequestedCount) + if tx_no_ack_requested_count is not None: + matter_asserts.assert_valid_uint32(tx_no_ack_requested_count, "TxNoAckRequestedCount") + + # + # STEP 8: Read TxDataCount + # + self.step(8) + tx_data_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxDataCount) + if tx_data_count is not None: + matter_asserts.assert_valid_uint32(tx_data_count, "TxDataCount") + + # + # STEP 9: Read TxDataPollCount + # + self.step(9) + tx_data_poll_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxDataPollCount) + if tx_data_poll_count is not None: + matter_asserts.assert_valid_uint32(tx_data_poll_count, "TxDataPollCount") + + # + # STEP 10: Read TxBeaconCount + # + self.step(10) + tx_beacon_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxBeaconCount) + if tx_beacon_count is not None: + matter_asserts.assert_valid_uint32(tx_beacon_count, "TxBeaconCount") + + # + # STEP 11: Read TxBeaconRequestCount + # + self.step(11) + tx_beacon_request_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxBeaconRequestCount) + if tx_beacon_request_count is not None: + matter_asserts.assert_valid_uint32(tx_beacon_request_count, "TxBeaconRequestCount") + + # + # STEP 12: Read TxOtherCount + # + self.step(12) + tx_other_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxOtherCount) + if tx_other_count is not None: + matter_asserts.assert_valid_uint32(tx_other_count, "TxOtherCount") + + # + # STEP 13: Read TxRetryCount + # + self.step(13) + tx_retry_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxRetryCount) + if tx_retry_count is not None: + matter_asserts.assert_valid_uint32(tx_retry_count, "TxRetryCount") + + # + # STEP 14: Read TxDirectMaxRetryExpiryCount + # + self.step(14) + tx_direct_max_retry_expiry_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxDirectMaxRetryExpiryCount) + if tx_direct_max_retry_expiry_count is not None: + matter_asserts.assert_valid_uint32(tx_direct_max_retry_expiry_count, "TxDirectMaxRetryExpiryCount") + + # + # STEP 15: Read TxIndirectMaxRetryExpiryCount + # + self.step(15) + tx_indirect_max_retry_expiry_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxIndirectMaxRetryExpiryCount) + if tx_indirect_max_retry_expiry_count is not None: + matter_asserts.assert_valid_uint32(tx_indirect_max_retry_expiry_count, "TxIndirectMaxRetryExpiryCount") + + # + # STEP 16: Read TxErrCcaCount + # + self.step(16) + tx_err_cca_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxErrCcaCount) + if tx_err_cca_count is not None: + matter_asserts.assert_valid_uint32(tx_err_cca_count, "TxErrCcaCount") + + # + # STEP 17: Read TxErrAbortCount + # + self.step(17) + tx_err_abort_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxErrAbortCount) + if tx_err_abort_count is not None: + matter_asserts.assert_valid_uint32(tx_err_abort_count, "TxErrAbortCount") + + # + # STEP 18: Read TxErrBusyChannelCount + # + self.step(18) + tx_err_busy_channel_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.TxErrBusyChannelCount) + if tx_err_busy_channel_count is not None: + matter_asserts.assert_valid_uint32(tx_err_busy_channel_count, "TxErrBusyChannelCount") + + +if __name__ == "__main__": + default_matter_test_main() From 64b110dc47e0f896f74113973f13f05953a195c3 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Fri, 24 Jan 2025 15:30:49 -0800 Subject: [PATCH 33/40] Implement python test for TC_DGTHREAD_2_3 (#37187) --- src/python_testing/TC_DGTHREAD_2_3.py | 243 ++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 src/python_testing/TC_DGTHREAD_2_3.py diff --git a/src/python_testing/TC_DGTHREAD_2_3.py b/src/python_testing/TC_DGTHREAD_2_3.py new file mode 100644 index 00000000000000..e370a1576d3ad6 --- /dev/null +++ b/src/python_testing/TC_DGTHREAD_2_3.py @@ -0,0 +1,243 @@ +# +# Copyright (c) 2025 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. +# + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${ALL_CLUSTERS_APP} +# app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# 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 +# factory-reset: true +# quiet: true +# === END CI TEST ARGUMENTS === +# + +import chip.clusters as Clusters +from chip.testing import matter_asserts +from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main + + +class TC_THREADND_2_3(MatterBaseTest): + """ + [TC-THREADND-2.3] Thread Network Diagnostics Cluster - Rx Attribute Read Verification + + This test case verifies the behavior of the Rx-related attributes of the Thread Network Diagnostics + cluster server (Server as DUT). The test case steps are derived from the provided + test plan specification. + """ + + async def read_thread_diagnostics_attribute_expect_success(self, endpoint, attribute): + """ + Convenience method to read a single ThreadNetworkDiagnostics attribute, + ensuring success. + """ + cluster = Clusters.Objects.ThreadNetworkDiagnostics + return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attribute) + + # + # --- Test Description, PICS, and Steps --- + # + def desc_TC_THREADND_2_3(self) -> str: + return "[TC-THREADND-2.3] Thread Network Diagnostics Rx Attributes with Server as DUT" + + def pics_TC_THREADND_2_3(self) -> list[str]: + return ["THREADND.S", "THREADND.SF.MACCNT"] # PICS identifiers for the test case + + def steps_TC_THREADND_2_3(self) -> list[TestStep]: + """ + Lists the test steps from the specification in an easy-to-read format. + """ + return [ + TestStep(1, "Commission DUT to TH (already done)", is_commissioning=True), + TestStep(2, "Read RxTotalCount attribute"), + TestStep(3, "Read RxUnicastCount attribute"), + TestStep(4, "Read RxBroadcastCount attribute"), + TestStep(5, "Read RxDataCount attribute"), + TestStep(6, "Read RxDataPollCount attribute"), + TestStep(7, "Read RxBeaconCount attribute"), + TestStep(8, "Read RxBeaconRequestCount attribute"), + TestStep(9, "Read RxOtherCount attribute"), + TestStep(10, "Read RxAddressFilteredCount attribute"), + TestStep(11, "Read RxDestAddrFilteredCount attribute"), + TestStep(12, "Read RxDuplicatedCount attribute"), + TestStep(13, "Read RxErrNoFrameCount attribute"), + TestStep(14, "Read RxErrUnknownNeighborCount attribute"), + TestStep(15, "Read RxErrInvalidSrcAddrCount attribute"), + TestStep(16, "Read RxErrSecCount attribute"), + TestStep(17, "Read RxErrFcsCount attribute"), + TestStep(18, "Read RxErrOtherCount attribute"), + ] + + # + # --- Main Test Routine --- + # + @async_test_body + async def test_TC_THREADND_2_3(self): + endpoint = self.get_endpoint(default=0) + attributes = Clusters.ThreadNetworkDiagnostics.Attributes + + # + # STEP 1: Commissioning (assumed done) + # + self.step(1) + # Normally performed by harness; no explicit code needed if already commissioned. + + # + # STEP 2: Read RxTotalCount + # + self.step(2) + rx_total_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxTotalCount) + if rx_total_count is not None: + matter_asserts.assert_valid_uint32(rx_total_count, "RxTotalCount") + + # + # STEP 3: Read RxUnicastCount + # + self.step(3) + rx_unicast_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxUnicastCount) + if rx_unicast_count is not None: + matter_asserts.assert_valid_uint32(rx_unicast_count, "RxUnicastCount") + + # + # STEP 4: Read RxBroadcastCount + # + self.step(4) + rx_broadcast_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxBroadcastCount) + if rx_broadcast_count is not None: + matter_asserts.assert_valid_uint32(rx_broadcast_count, "RxBroadcastCount") + + # + # STEP 5: Read RxDataCount + # + self.step(5) + rx_data_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxDataCount) + if rx_data_count is not None: + matter_asserts.assert_valid_uint32(rx_data_count, "RxDataCount") + + # + # STEP 6: Read RxDataPollCount + # + self.step(6) + rx_data_poll_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxDataPollCount) + if rx_data_poll_count is not None: + matter_asserts.assert_valid_uint32(rx_data_poll_count, "RxDataPollCount") + + # + # STEP 7: Read RxBeaconCount + # + self.step(7) + rx_beacon_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxBeaconCount) + if rx_beacon_count is not None: + matter_asserts.assert_valid_uint32(rx_beacon_count, "RxBeaconCount") + + # + # STEP 8: Read RxBeaconRequestCount + # + self.step(8) + rx_beacon_request_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxBeaconRequestCount) + if rx_beacon_request_count is not None: + matter_asserts.assert_valid_uint32(rx_beacon_request_count, "RxBeaconRequestCount") + + # + # STEP 9: Read RxOtherCount + # + self.step(9) + rx_other_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxOtherCount) + if rx_other_count is not None: + matter_asserts.assert_valid_uint32(rx_other_count, "RxOtherCount") + + # + # STEP 10: Read RxAddressFilteredCount + # + self.step(10) + rx_address_filtered_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxAddressFilteredCount) + if rx_address_filtered_count is not None: + matter_asserts.assert_valid_uint32(rx_address_filtered_count, "RxAddressFilteredCount") + + # + # STEP 11: Read RxDestAddrFilteredCount + # + self.step(11) + rx_dest_addr_filtered_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxDestAddrFilteredCount) + if rx_dest_addr_filtered_count is not None: + matter_asserts.assert_valid_uint32(rx_dest_addr_filtered_count, "RxDestAddrFilteredCount") + + # + # STEP 12: Read RxDuplicatedCount + # + self.step(12) + rx_duplicated_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxDuplicatedCount) + if rx_duplicated_count is not None: + matter_asserts.assert_valid_uint32(rx_duplicated_count, "RxDuplicatedCount") + + # + # STEP 13: Read RxErrNoFrameCount + # + self.step(13) + rx_err_no_frame_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxErrNoFrameCount) + if rx_err_no_frame_count is not None: + matter_asserts.assert_valid_uint32(rx_err_no_frame_count, "RxErrNoFrameCount") + + # + # STEP 14: Read RxErrUnknownNeighborCount + # + self.step(14) + rx_err_unknown_neighbor_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxErrUnknownNeighborCount) + if rx_err_unknown_neighbor_count is not None: + matter_asserts.assert_valid_uint32(rx_err_unknown_neighbor_count, "RxErrUnknownNeighborCount") + + # + # STEP 15: Read RxErrInvalidSrcAddrCount + # + self.step(15) + rx_err_invalid_src_addr_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxErrInvalidSrcAddrCount) + if rx_err_invalid_src_addr_count is not None: + matter_asserts.assert_valid_uint32(rx_err_invalid_src_addr_count, "RxErrInvalidSrcAddrCount") + + # + # STEP 16: Read RxErrSecCount + # + self.step(16) + rx_err_sec_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxErrSecCount) + if rx_err_sec_count is not None: + matter_asserts.assert_valid_uint32(rx_err_sec_count, "RxErrSecCount") + + # + # STEP 17: Read RxErrFcsCount + # + self.step(17) + rx_err_fcs_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxErrFcsCount) + if rx_err_fcs_count is not None: + matter_asserts.assert_valid_uint32(rx_err_fcs_count, "RxErrFcsCount") + + # + # STEP 18: Read RxErrOtherCount + # + self.step(18) + rx_err_other_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.RxErrOtherCount) + if rx_err_other_count is not None: + matter_asserts.assert_valid_uint32(rx_err_other_count, "RxErrOtherCount") + + +if __name__ == "__main__": + default_matter_test_main() From 12235cdaf3eb857cc0525e26923d1e2b2b2e49b2 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Fri, 24 Jan 2025 15:31:14 -0800 Subject: [PATCH 34/40] Implement python test for TC_DGTHREAD_2_4 (#37194) --- src/python_testing/TC_DGTHREAD_2_4.py | 97 +++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 src/python_testing/TC_DGTHREAD_2_4.py diff --git a/src/python_testing/TC_DGTHREAD_2_4.py b/src/python_testing/TC_DGTHREAD_2_4.py new file mode 100644 index 00000000000000..4fe9bd2558b6e3 --- /dev/null +++ b/src/python_testing/TC_DGTHREAD_2_4.py @@ -0,0 +1,97 @@ +# +# Copyright (c) 2025 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. +# + +# === BEGIN CI TEST ARGUMENTS === +# test-runner-runs: +# run1: +# app: ${ALL_CLUSTERS_APP} +# app-args: --discriminator 1234 --KVS kvs1 --trace-to json:${TRACE_APP}.json +# 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 +# factory-reset: true +# quiet: true +# === END CI TEST ARGUMENTS === +# + +import chip.clusters as Clusters +from chip.testing.matter_testing import MatterBaseTest, TestStep, async_test_body, default_matter_test_main +from mobly import asserts + + +class TC_THREADND_2_4(MatterBaseTest): + """ + [TC-DGTHREAD-2.4] ResetCounts Command Verification with Server as DUT + + This test case verifies the ResetCounts command and subsequent OverrunCount attribute behavior. + """ + + async def send_reset_counts_command(self, endpoint): + """Sends the ResetCounts command to the DUT.""" + cluster = Clusters.Objects.ThreadNetworkDiagnostics + await self.send_single_cmd(cluster.Commands.ResetCounts(), endpoint=endpoint) + + async def read_thread_diagnostics_attribute_expect_success(self, endpoint, attribute): + """ + Convenience method to read a single ThreadNetworkDiagnostics attribute, + ensuring success. + """ + cluster = Clusters.Objects.ThreadNetworkDiagnostics + return await self.read_single_attribute_check_success(endpoint=endpoint, cluster=cluster, attribute=attribute) + + def desc_TC_THREADND_2_4(self) -> str: + """Returns a description of this test.""" + return "[TC-DGWIFI-2.4] ResetCounts Command Verification with Server as DUT" + + def pics_TC_THREADND_2_4(self) -> list[str]: + return ["DGWIFI.S", "DGWIFI.S.F.ERRCNT"] + + def steps_TC_THREADND_2_4(self) -> list[TestStep]: + steps = [ + TestStep("1", "Commission DUT to TH (already done)", is_commissioning=True), + TestStep("2", "TH sends ResetCounts Command to DUT"), + TestStep("3", "TH reads OverrunCount attribute from DUT"), + ] + return steps + + @async_test_body + async def test_TC_THREADND_2_4(self): + endpoint = self.get_endpoint(default=0) + + # STEP 1: Commission DUT (already done) + self.step("1") + # Typically, we assume commissioning was performed by harness scripts. + attributes = Clusters.ThreadNetworkDiagnostics.Attributes + + # STEP 2: Send ResetCounts command + self.step("2") + await self.send_reset_counts_command(endpoint) + + # STEP 3: Verify OverrunCount attribute + self.step("3") + overrun_count = await self.read_thread_diagnostics_attribute_expect_success(endpoint, attributes.OverrunCount) + if overrun_count is not None: + # Verify that the OverrunCount is set to Zero + asserts.assert_true(overrun_count == 0, "OverrunCount should be set to Zero") + + +if __name__ == "__main__": + default_matter_test_main() From fd216ecbf0efd056cb1a8acafb4c0228b0def400 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 24 Jan 2025 18:55:28 -0500 Subject: [PATCH 35/40] Add a way to forget a node ID to Matter.framework. (#37198) The intent is to tear down any MTRDevice connection to the node and remove any stored data for the node ID. --- .../Framework/CHIP/MTRDeviceController.h | 6 +++ .../Framework/CHIP/MTRDeviceController.mm | 12 +++++ .../CHIP/MTRDeviceControllerDataStore.h | 2 + .../CHIP/MTRDeviceControllerDataStore.mm | 54 ++++++++++++++----- .../CHIP/MTRDeviceController_Concrete.mm | 15 ++++++ .../Framework/CHIP/MTRDeviceController_XPC.mm | 11 ++++ .../CHIP/XPC Protocol/MTRXPCServerProtocol.h | 2 + .../CHIPTests/MTRPerControllerStorageTests.m | 16 ++++++ .../TestHelpers/MTRTestDeclarations.h | 4 ++ 9 files changed, 109 insertions(+), 13 deletions(-) diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.h b/src/darwin/Framework/CHIP/MTRDeviceController.h index 3ad0c37ea025bb..f9d0cd3d5196d7 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.h +++ b/src/darwin/Framework/CHIP/MTRDeviceController.h @@ -269,6 +269,12 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) */ - (void)removeServerEndpoint:(MTRServerEndpoint *)endpoint MTR_AVAILABLE(ios(17.6), macos(14.6), watchos(10.6), tvos(17.6)); +/** + * Forget any information we have about the device with the given node ID. That + * includes clearing any information we have stored about it. + */ +- (void)forgetDeviceWithNodeID:(NSNumber *)nodeID MTR_NEWLY_AVAILABLE; + /** * Compute a PASE verifier for the desired setup passcode. * diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index 2380a5af846ff1..7bdbf2302740e9 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -386,6 +386,18 @@ - (MTRDevice *)deviceForNodeID:(NSNumber *)nodeID return [self _deviceForNodeID:nodeID createIfNeeded:YES]; } +- (void)forgetDeviceWithNodeID:(NSNumber *)nodeID +{ + MTRDevice * deviceToRemove; + { + std::lock_guard lock(*self.deviceMapLock); + deviceToRemove = [_nodeIDToDeviceMap objectForKey:nodeID]; + } + if (deviceToRemove != nil) { + [self removeDevice:deviceToRemove]; + } +} + - (void)removeDevice:(MTRDevice *)device { std::lock_guard lock(*self.deviceMapLock); diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.h b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.h index 943cd4c2cfb33c..f4f38855420345 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.h +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.h @@ -61,6 +61,7 @@ typedef void (^MTRDeviceControllerDataStoreClusterDataHandler)(NSDictionary *)getStoredDeviceDataForNodeID:(NSNumber *)nodeID; - (void)storeDeviceData:(NSDictionary *)data forNodeID:(NSNumber *)nodeID; +- (void)clearDeviceDataForNodeID:(NSNumber *)nodeID; /** * Mechanism for an API client to perform a block after previous async operations (writes) on the storage queue have executed. diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm index a874e26f44f428..7ca30225b84f88 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerDataStore.mm @@ -228,24 +228,38 @@ - (void)clearAllResumptionInfo // Can we do less dispatch? We would need to have a version of // _findResumptionInfoWithKey that assumes we are already on the right queue. for (NSNumber * nodeID in _nodesWithResumptionInfo) { - auto * oldInfo = [self findResumptionInfoByNodeID:nodeID]; - if (oldInfo != nil) { - dispatch_sync(_storageDelegateQueue, ^{ - [_storageDelegate controller:controller - removeValueForKey:ResumptionByResumptionIDKey(oldInfo.resumptionID) - securityLevel:MTRStorageSecurityLevelSecure - sharingType:MTRStorageSharingTypeNotShared]; - [_storageDelegate controller:controller - removeValueForKey:ResumptionByNodeIDKey(oldInfo.nodeID) - securityLevel:MTRStorageSecurityLevelSecure - sharingType:MTRStorageSharingTypeNotShared]; - }); - } + [self _clearResumptionInfoForNodeID:nodeID controller:controller]; } [_nodesWithResumptionInfo removeAllObjects]; } +- (void)clearResumptionInfoForNodeID:(NSNumber *)nodeID +{ + MTRDeviceController * controller = _controller; + VerifyOrReturn(controller != nil); // No way to call delegate without controller. + + [self _clearResumptionInfoForNodeID:nodeID controller:controller]; + [_nodesWithResumptionInfo removeObject:nodeID]; +} + +- (void)_clearResumptionInfoForNodeID:(NSNumber *)nodeID controller:(MTRDeviceController *)controller +{ + auto * oldInfo = [self findResumptionInfoByNodeID:nodeID]; + if (oldInfo != nil) { + dispatch_sync(_storageDelegateQueue, ^{ + [_storageDelegate controller:controller + removeValueForKey:ResumptionByResumptionIDKey(oldInfo.resumptionID) + securityLevel:MTRStorageSecurityLevelSecure + sharingType:MTRStorageSharingTypeNotShared]; + [_storageDelegate controller:controller + removeValueForKey:ResumptionByNodeIDKey(oldInfo.nodeID) + securityLevel:MTRStorageSecurityLevelSecure + sharingType:MTRStorageSharingTypeNotShared]; + }); + } +} + - (CHIP_ERROR)storeLastLocallyUsedNOC:(MTRCertificateTLVBytes)noc { MTRDeviceController * controller = _controller; @@ -1169,6 +1183,20 @@ - (void)storeDeviceData:(NSDictionary *)data forNodeID:(NSNumber }); } +- (void)clearDeviceDataForNodeID:(NSNumber *)nodeID +{ + dispatch_async(_storageDelegateQueue, ^{ + MTRDeviceController * controller = self->_controller; + VerifyOrReturn(controller != nil); // No way to call delegate without controller. + + // Ignore store failures, since they are not actionable for us here. + [self->_storageDelegate controller:controller + removeValueForKey:[self _deviceDataKeyForNodeID:nodeID] + securityLevel:MTRStorageSecurityLevelSecure + sharingType:MTRStorageSharingTypeNotShared]; + }); +} + - (void)synchronouslyPerformBlock:(void (^_Nullable)(void))block { dispatch_sync(_storageDelegateQueue, ^{ diff --git a/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm b/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm index b67b07e8b81ba3..4c427e7dd9fbcb 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.mm @@ -1193,6 +1193,21 @@ - (MTRDevice *)_setupDeviceForNodeID:(NSNumber *)nodeID prefetchedClusterData:(N return deviceToReturn; } +- (void)forgetDeviceWithNodeID:(NSNumber *)nodeID +{ + MTR_LOG("%@: Forgetting device with node ID: %@", self, nodeID); + + // Tear down any existing MTRDevice for this nodeID first, so we don't run + // into issues with it storing data after we have deleted it. + [super forgetDeviceWithNodeID:nodeID]; + + if (_controllerDataStore) { + [_controllerDataStore clearResumptionInfoForNodeID:nodeID]; + [_controllerDataStore clearDeviceDataForNodeID:nodeID]; + [_controllerDataStore clearStoredClusterDataForNodeID:nodeID]; + } +} + #ifdef DEBUG - (NSDictionary *)unitTestGetDeviceAttributeCounts { diff --git a/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm b/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm index 827dad526025d0..72c7151355021c 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController_XPC.mm @@ -60,6 +60,10 @@ @implementation MTRDeviceController_XPC : (NSDictionary *) controllerState, updateControllerConfiguration : (NSDictionary *) controllerState) +MTR_DEVICECONTROLLER_SIMPLE_REMOTE_XPC_COMMAND(deleteNodeID + : (NSNumber *) nodeID, deleteNodeID + : (NSNumber *) nodeID) + - (void)_updateRegistrationInfo { NSMutableDictionary * registrationInfo = [NSMutableDictionary dictionary]; @@ -95,6 +99,13 @@ - (void)removeDevice:(MTRDevice *)device [self _updateRegistrationInfo]; } +- (void)forgetDeviceWithNodeID:(NSNumber *)nodeID +{ + MTR_LOG("%@: Forgetting device with node ID: %@", self, nodeID); + [self deleteNodeID:nodeID]; + [super forgetDeviceWithNodeID:nodeID]; +} + #pragma mark - XPC @synthesize controllerNodeID = _controllerNodeID; @synthesize compressedFabricID = _compressedFabricID; diff --git a/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCServerProtocol.h b/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCServerProtocol.h index 45d19185d9184e..9da4fd6ccda453 100644 --- a/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCServerProtocol.h +++ b/src/darwin/Framework/CHIP/XPC Protocol/MTRXPCServerProtocol.h @@ -71,6 +71,8 @@ MTR_AVAILABLE(ios(18.2), macos(15.2), watchos(11.2), tvos(18.2)) // - (oneway void)deviceController:(NSUUID *)controller addServerEndpoint:(MTRServerEndpoint *)endpoint withReply:(void (^)(BOOL success))reply; // - (oneway void)deviceController:(NSUUID *)controller removeServerEndpoint:(MTRServerEndpoint *)endpoint; +- (oneway void)deviceController:(NSUUID *)controller deleteNodeID:(NSNumber *)nodeID MTR_NEWLY_AVAILABLE; + - (oneway void)deviceController:(NSUUID *)controller registerNodeID:(NSNumber *)nodeID; - (oneway void)deviceController:(NSUUID *)controller unregisterNodeID:(NSNumber *)nodeID; - (oneway void)deviceController:(NSUUID *)controller updateControllerConfiguration:(NSDictionary *)controllerState; diff --git a/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m b/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m index 27ba035a100548..2abfda4fee4b8b 100644 --- a/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m +++ b/src/darwin/Framework/CHIPTests/MTRPerControllerStorageTests.m @@ -1764,6 +1764,22 @@ - (void)test010_TestDataStoreMTRDeviceWithBulkReadWrite } XCTAssertTrue(totalAttributes > 300); + // Now try forgetting this device and make sure all the info we had for it + // goes away. + NSNumber * deviceID = @(17); + __auto_type * dataStore = controller.controllerDataStore; + XCTAssertNotNil(deviceAttributeCounts[deviceID]); + XCTAssertNotNil([dataStore findResumptionInfoByNodeID:deviceID]); + XCTAssertNotNil([dataStore getStoredDeviceDataForNodeID:deviceID]); + XCTAssertNotNil([dataStore getStoredClusterDataForNodeID:deviceID]); + + [controller forgetDeviceWithNodeID:deviceID]; + deviceAttributeCounts = [controller unitTestGetDeviceAttributeCounts]; + XCTAssertNil(deviceAttributeCounts[deviceID]); + XCTAssertNil([dataStore findResumptionInfoByNodeID:deviceID]); + XCTAssertNil([dataStore getStoredDeviceDataForNodeID:deviceID]); + XCTAssertNil([dataStore getStoredClusterDataForNodeID:deviceID]); + [controller shutdown]; XCTAssertFalse([controller isRunning]); } diff --git a/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestDeclarations.h b/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestDeclarations.h index 591110b34ea712..e2a9ae76df964e 100644 --- a/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestDeclarations.h +++ b/src/darwin/Framework/CHIPTests/TestHelpers/MTRTestDeclarations.h @@ -26,8 +26,11 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - Declarations for internal methods +@class MTRCASESessionResumptionInfo; + // MTRDeviceControllerDataStore.h includes C++ header, and so we need to declare the methods separately @protocol MTRDeviceControllerDataStoreAttributeStoreMethods +- (nullable MTRCASESessionResumptionInfo *)findResumptionInfoByNodeID:(NSNumber *)nodeID; - (nullable NSDictionary *)getStoredClusterDataForNodeID:(NSNumber *)nodeID; - (void)storeClusterData:(NSDictionary *)clusterData forNodeID:(NSNumber *)nodeID; - (void)clearStoredClusterDataForNodeID:(NSNumber *)nodeID; @@ -39,6 +42,7 @@ NS_ASSUME_NONNULL_BEGIN - (nullable NSArray *)_fetchEndpointIndexForNodeID:(NSNumber *)nodeID; - (nullable NSArray *)_fetchClusterIndexForNodeID:(NSNumber *)nodeID endpointID:(NSNumber *)endpointID; - (nullable MTRDeviceClusterData *)_fetchClusterDataForNodeID:(NSNumber *)nodeID endpointID:(NSNumber *)endpointID clusterID:(NSNumber *)clusterID; +- (nullable NSDictionary *)getStoredDeviceDataForNodeID:(NSNumber *)nodeID; @end // Declare internal methods for testing From 5dee6838dd76e5739d36a9a71b2e83221e6a655e Mon Sep 17 00:00:00 2001 From: Jeff Tung <100387939+jtung-apple@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:46:12 -0800 Subject: [PATCH 36/40] [Darwin] Fix return type of unit test to standard type (#37200) --- src/darwin/Framework/CHIPTests/MTRSetupPayloadTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/darwin/Framework/CHIPTests/MTRSetupPayloadTests.m b/src/darwin/Framework/CHIPTests/MTRSetupPayloadTests.m index df99c3b7cda8c1..df2ed3ae11a30e 100644 --- a/src/darwin/Framework/CHIPTests/MTRSetupPayloadTests.m +++ b/src/darwin/Framework/CHIPTests/MTRSetupPayloadTests.m @@ -439,7 +439,7 @@ - (void)testDescriptionShowsUnknownDiscoveryMethods XCTAssertNotEqualObjects(a.description, b.description); } -- (uint32)generateRepeatedDigitPasscode:(uint8_t)digit +- (uint32_t)generateRepeatedDigitPasscode:(uint8_t)digit { // "digit" is expected to be a single digit. Generates a number that has // that digit repeated 8 times. From 8ef6bb40eaf79f1a5c8adcf60abe0af83c3a8ff5 Mon Sep 17 00:00:00 2001 From: C Freeman Date: Sat, 25 Jan 2025 12:38:09 -0500 Subject: [PATCH 37/40] Python testing: Handle provisional aliased clusters (#37192) Handle the case where there are cluster aliases, and only some of the aliased clusters are provisional. This is a weird case that only happens in the 1.3 spec, which was before we handled provisional in the automated testing. Test: See attached unit tests. Level control is now correctly marked in 1.3. --- src/python_testing/TestSpecParsingSupport.py | 8 +++++++- .../chip/testing/spec_parsing.py | 7 ++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/python_testing/TestSpecParsingSupport.py b/src/python_testing/TestSpecParsingSupport.py index 7ab5847a276883..3b446f1996d8b2 100644 --- a/src/python_testing/TestSpecParsingSupport.py +++ b/src/python_testing/TestSpecParsingSupport.py @@ -213,7 +213,9 @@ def get_access_enum_from_string(access_str: str) -> Clusters.AccessControl.Enums ' ' ' ' ' ' - ' ' + ' ' + ' ' + ' ' ' ' ' ' ' ' @@ -396,6 +398,10 @@ def test_aliased_clusters(self): asserts.assert_true((0xFFFE, 'Test Alias1') in ids, "Unable to find Test Alias1 cluster in parsed clusters") asserts.assert_true((0xFFFD, 'Test Alias2') in ids, "Unable to find Test Alias2 cluster in parsed clusters") + # Test Alias2 is marked as provisional, and TestAlias1 is not + asserts.assert_false(clusters[0xFFFE].is_provisional, "Test Alias1 is marked as provisional and should not be") + asserts.assert_true(clusters[0xFFFD].is_provisional, "Test Alias2 is not marked as provisional and should be") + def test_known_aliased_clusters(self): known_aliased_clusters = set([(0x040C, 'Carbon Monoxide Concentration Measurement', 'CMOCONC'), (0x040D, 'Carbon Dioxide Concentration Measurement', 'CDOCONC'), diff --git a/src/python_testing/matter_testing_infrastructure/chip/testing/spec_parsing.py b/src/python_testing/matter_testing_infrastructure/chip/testing/spec_parsing.py index 7bd247746a07e5..56c777868d3d87 100644 --- a/src/python_testing/matter_testing_infrastructure/chip/testing/spec_parsing.py +++ b/src/python_testing/matter_testing_infrastructure/chip/testing/spec_parsing.py @@ -228,9 +228,10 @@ def __init__(self, cluster: ElementTree.Element, cluster_id: Optional[uint], nam except (KeyError, StopIteration): self._derived = None - for id in cluster.iter('clusterIds'): - if list(id.iter('provisionalConform')): - self._is_provisional = True + for ids in cluster.iter('clusterIds'): + for id in ids.iter('clusterId'): + if id.attrib['name'] == name and list(id.iter('provisionalConform')): + self._is_provisional = True self._pics: Optional[str] = None try: From 22cd392997869f430d5113fed3957688331e7faf Mon Sep 17 00:00:00 2001 From: senthilku Date: Sun, 26 Jan 2025 01:25:36 +0530 Subject: [PATCH 38/40] Updating the firmware upgrade status for SoC (#37132) --- src/platform/silabs/SiWx917/OTAImageProcessorImpl.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/platform/silabs/SiWx917/OTAImageProcessorImpl.cpp b/src/platform/silabs/SiWx917/OTAImageProcessorImpl.cpp index 97b06f2aab323e..6c2a90f705a18a 100644 --- a/src/platform/silabs/SiWx917/OTAImageProcessorImpl.cpp +++ b/src/platform/silabs/SiWx917/OTAImageProcessorImpl.cpp @@ -36,7 +36,6 @@ extern "C" { #define RPS_HEADER 1 #define RPS_DATA 2 -#define SL_STATUS_FW_UPDATE_DONE SL_STATUS_SI91X_NO_AP_FOUND uint8_t flag = RPS_HEADER; static chip::OTAImageProcessorImpl gImageProcessor; @@ -186,13 +185,13 @@ void OTAImageProcessorImpl::HandleFinalize(intptr_t context) if (status != SL_STATUS_OK) { - if (status == SL_STATUS_FW_UPDATE_DONE) + if (status == SL_STATUS_SI91X_FW_UPDATE_DONE) { mReset = true; } else { - ChipLogError(SoftwareUpdate, "ERROR: In HandleFinalize for last chunk sl_si91x_fwup_load() error %ld", status); + ChipLogError(SoftwareUpdate, "ERROR: In HandleFinalize for last chunk sl_si91x_fwup_load() error 0x%lx", status); imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED); return; } @@ -315,13 +314,13 @@ void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) { // If the last chunk of last block-writeBufOffset length is exactly kAlignmentBytes(64) bytes then mReset value // should be set to true in HandleProcessBlock - if (status == SL_STATUS_FW_UPDATE_DONE) + if (status == SL_STATUS_SI91X_FW_UPDATE_DONE) { mReset = true; } else { - ChipLogError(SoftwareUpdate, "ERROR: In HandleProcessBlock sl_si91x_fwup_load() error %ld", status); + ChipLogError(SoftwareUpdate, "ERROR: In HandleProcessBlock sl_si91x_fwup_load() error 0x%lx", status); imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED); return; } From d21aaa566aa318ed1307bbeeb777bc947fe15fb5 Mon Sep 17 00:00:00 2001 From: Maciej Grela Date: Mon, 27 Jan 2025 14:58:25 +0100 Subject: [PATCH 39/40] devcontainer: Modernize devcontainer, bump version (#37142) * devcontainer: Modernize devcontainer, bump version - bump base image versions to 97 to match CI - convert some of the runCmd docker options into dedicated properties Signed-off-by: Maciej Grela * retry darwin * devcontainer: Bind dbus system bus for BLE commissioning Signed-off-by: Maciej Grela * Revert "devcontainer: Bind dbus system bus for BLE commissioning" This reverts commit 28897b6e20610c335cbc828d50b45f35dd11d86b. --------- Signed-off-by: Maciej Grela --- .devcontainer/devcontainer.json | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 9c7f6aeaef881b..56bb094d004652 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,20 +1,26 @@ { "name": "CHIP Ubuntu Development Environment", "runArgs": [ - "--cap-add=SYS_PTRACE", - "--security-opt", - "seccomp=unconfined", "--network=host", - "--privileged", - "-v", - "/dev/bus/usb:/dev/bus/usb:ro", "--device-cgroup-rule=a 189:* rmw", "--add-host=host.docker.internal:host-gateway" ], + "privileged": true, + "capAdd": ["SYS_PTRACE"], + "securityOpt": ["seccomp=unconfined"], "mounts": [ - "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" + { + "source": "/var/run/docker.sock", + "target": "/var/run/docker.sock", + "type": "bind" + }, + { + "source": "/dev/bus/usb", + "target": "/dev/bus/usb", + "type": "bind" + } ], - "initializeCommand": "bash .devcontainer/build.sh --tag matter-dev-environment:local --version 74", + "initializeCommand": "bash .devcontainer/build.sh --tag matter-dev-environment:local --version 97", "image": "matter-dev-environment:local", "remoteUser": "vscode", "containerEnv": { From 0c1a6063f6d80c99e60d13462c89ab44018fb9b6 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 27 Jan 2025 13:20:10 -0500 Subject: [PATCH 40/40] Fix thread race in test008_pairingAfterCancellation_DeviceAttestationVerification (#37191) The attestation delegate is called on some random framework-internal queue, so it setting the boolean could race with the test main body reading the boolean, which could cause TSan failures, as well as outright failures in some cases. Adding a sleep(5) into the delegate callback before setting the boolean made the test fail reliably. The fix is to just use an expectation to track the "has the delegate been called?" state, since that will handle synchronization for us. --- src/darwin/Framework/CHIPTests/MTRPairingTests.m | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/darwin/Framework/CHIPTests/MTRPairingTests.m b/src/darwin/Framework/CHIPTests/MTRPairingTests.m index e0bac5f2a74ac7..4aade77a11db4f 100644 --- a/src/darwin/Framework/CHIPTests/MTRPairingTests.m +++ b/src/darwin/Framework/CHIPTests/MTRPairingTests.m @@ -480,14 +480,15 @@ - (void)test007_pairingAfterCancellation_FindOperational - (void)test008_pairingAfterCancellation_DeviceAttestationVerification { // Cancel pairing while we are waiting for our client to decide what to do - // with the attestation information we got. - __block BOOL delegateCalled = NO; - __auto_type * attestationDelegate = [[NoOpAttestationDelegate alloc] initWithCallback:^{ - delegateCalled = YES; - } blockCommissioning:YES]; + // with the attestation information we got. Note that the delegate is + // called on some arbitrary queue, so we need to make sure we wait for it to + // actually be called; we can't just have it set a boolean that we then + // check, because that can race. + XCTestExpectation * expectation = [self expectationWithDescription:@"Attestation delegate called"]; + __auto_type * attestationDelegate = [[NoOpAttestationDelegate alloc] initWithExpectation:expectation blockCommissioning:YES]; [self doPairingTestAfterCancellationAtProgress:@"Successfully extended fail-safe timer to handle DA failure" attestationDelegate:attestationDelegate]; - XCTAssertTrue(delegateCalled); + [self waitForExpectations:@[ expectation ] timeout:kPairingTimeoutInSeconds]; } - (void)test009_PairWithReadingEndpointInformation