From 17f25a1772f7ba7535d57cd4dfa43ac1fc295843 Mon Sep 17 00:00:00 2001 From: Amine Alami <43780877+Alami-Amine@users.noreply.github.com> Date: Mon, 23 Sep 2024 19:09:55 +0200 Subject: [PATCH 01/19] Bugfix: packet buffer counter going negative and triggering UBSan Issue (#35708) * Fix for issue where the packet buffer counter (sResourcesInUse[kSystemLayer_NumPacketBufs]) in SystemStats is going negative and underflowing, triggering a UBSan issue during fuzzing * Integrating comments --- src/system/SystemPacketBuffer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/system/SystemPacketBuffer.cpp b/src/system/SystemPacketBuffer.cpp index 20bd93540afe62..79e1bd25a67d8a 100644 --- a/src/system/SystemPacketBuffer.cpp +++ b/src/system/SystemPacketBuffer.cpp @@ -151,6 +151,8 @@ void PacketBufferHandle::InternalRightSize() return; } + SYSTEM_STATS_INCREMENT(chip::System::Stats::kSystemLayer_NumPacketBufs); + uint8_t * const newStart = newBuffer->ReserveStart(); newBuffer->next = nullptr; newBuffer->payload = newStart + (payload - start); From 8750c554965758892de96549b34d470ecf528fb0 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 23 Sep 2024 14:20:36 -0400 Subject: [PATCH 02/19] Stop using MinInterval = 2 in tests that expect reports within 3 seconds. (#35707) We had a bunch of subscription Darwin tests that set a 2-second MinInterval but expected reports within 3 seconds. This seems to have worked because for some reason the 2-second timers fired pretty early (at closer to 1.5 seconds) on the existing runners, but on the new ARM runners it actually fires at 2 seconds, and then we have a very high test timeout rate. The fix is to just use a MinInterval of 0 for the relevant subscriptions. test012_SubscribeKeepingPreviousSubscription turned out to be relying on not getting reports from when it sends the Off command until it sends the followup On command, but now we do in fact send those reports. So we need to wait for them to clear through before we send the On command. --- .../Framework/CHIPTests/MTRDeviceTests.m | 4 +- .../CHIPTests/MTRXPCListenerSampleTests.m | 72 +++++++++++++++---- 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m index dda8986e33aaaa..1fb580488f6c51 100644 --- a/src/darwin/Framework/CHIPTests/MTRDeviceTests.m +++ b/src/darwin/Framework/CHIPTests/MTRDeviceTests.m @@ -815,7 +815,7 @@ - (void)test011_ReadCachedAttribute NSLog(@"Subscribing..."); // reportHandler returns TRUE if it got the things it was looking for or if there's an error. __block BOOL (^reportHandler)(NSArray * _Nullable value, NSError * _Nullable error); - __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(2) maxInterval:@(60)]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(0) maxInterval:@(60)]; params.resubscribeAutomatically = NO; [device subscribeWithQueue:queue params:params @@ -881,7 +881,7 @@ - (void)test011_ReadCachedAttribute // Add another subscriber of the attribute to verify that attribute cache still works when there are other subscribers. NSLog(@"New subscription..."); XCTestExpectation * newSubscriptionEstablished = [self expectationWithDescription:@"New subscription established"]; - MTRSubscribeParams * newParams = [[MTRSubscribeParams alloc] initWithMinInterval:@(2) maxInterval:@(60)]; + MTRSubscribeParams * newParams = [[MTRSubscribeParams alloc] initWithMinInterval:@(0) maxInterval:@(60)]; newParams.replaceExistingSubscriptions = NO; newParams.resubscribeAutomatically = NO; [cluster subscribeAttributeOnOffWithParams:newParams diff --git a/src/darwin/Framework/CHIPTests/MTRXPCListenerSampleTests.m b/src/darwin/Framework/CHIPTests/MTRXPCListenerSampleTests.m index 78a26dba56e880..f16775af0f9d95 100644 --- a/src/darwin/Framework/CHIPTests/MTRXPCListenerSampleTests.m +++ b/src/darwin/Framework/CHIPTests/MTRXPCListenerSampleTests.m @@ -758,7 +758,7 @@ - (void)test004_Subscribe MTRBaseDevice * device = GetConnectedDevice(); dispatch_queue_t queue = dispatch_get_main_queue(); - __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(2) maxInterval:@(10)]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(0) maxInterval:@(10)]; [device subscribeToAttributesWithEndpointID:@1 clusterID:@6 attributeID:@0 @@ -958,7 +958,7 @@ - (void)test008_SubscribeFailure MTRBaseDevice * device = GetConnectedDevice(); dispatch_queue_t queue = dispatch_get_main_queue(); - __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(2) maxInterval:@(10)]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(0) maxInterval:@(10)]; params.resubscribeAutomatically = NO; [device subscribeToAttributesWithEndpointID:@10000 clusterID:@6 @@ -1039,7 +1039,7 @@ - (void)test010_SubscribeWithNoParams // Subscribe XCTestExpectation * subscribeExpectation = [self expectationWithDescription:@"subscribe OnOff attribute"]; - __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(2) maxInterval:@(10)]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(0) maxInterval:@(10)]; [device subscribeToAttributesWithEndpointID:@1 clusterID:@6 attributeID:@0 @@ -1064,7 +1064,7 @@ - (void)test010_SubscribeWithNoParams // Setup 2nd subscriber subscribeExpectation = [self expectationWithDescription:@"subscribe CurrentLevel attribute"]; - params = [[MTRSubscribeParams alloc] initWithMinInterval:@(2) maxInterval:@(10)]; + params = [[MTRSubscribeParams alloc] initWithMinInterval:@(0) maxInterval:@(10)]; [device subscribeToAttributesWithEndpointID:@1 clusterID:@8 attributeID:@0 @@ -1212,7 +1212,7 @@ - (void)test011_SubscribeWithParams // Subscribe XCTestExpectation * subscribeExpectation = [self expectationWithDescription:@"subscribe OnOff attribute"]; - __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(2) maxInterval:@(10)]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(0) maxInterval:@(10)]; [device subscribeToAttributesWithEndpointID:@1 clusterID:@6 attributeID:@0 @@ -1236,7 +1236,7 @@ - (void)test011_SubscribeWithParams [self waitForExpectations:@[ subscribeExpectation ] timeout:kTimeoutInSeconds]; // Setup 2nd subscriber - MTRSubscribeParams * myParams = [[MTRSubscribeParams alloc] initWithMinInterval:@(2) maxInterval:@(10)]; + MTRSubscribeParams * myParams = [[MTRSubscribeParams alloc] initWithMinInterval:@(0) maxInterval:@(10)]; myParams.replaceExistingSubscriptions = YES; subscribeExpectation = [self expectationWithDescription:@"subscribe CurrentLevel attribute"]; [device subscribeToAttributesWithEndpointID:@1 @@ -1390,10 +1390,31 @@ - (void)test012_SubscribeKeepingPreviousSubscription __block void (^firstReportHandler)(id _Nullable values, NSError * _Nullable error) = nil; __block void (^secondReportHandler)(id _Nullable values, NSError * _Nullable error) = nil; + // Depending on how this test is run (alone or after other tests), we might + // be either in the "On" or "Off" state when we start. Track that, so we + // can ensure we're in the "Off" state correctly later. + __block BOOL initialOnOffState; + + XCTestExpectation * initialOnOffReportExpectation = [self expectationWithDescription:@"initial OnOff report expectation"]; + firstReportHandler = ^(id _Nullable values, NSError * _Nullable error) { + XCTAssertNil(error); + + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSDictionary * result = values[0]; + MTRAttributePath * path = result[@"attributePath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 6); + XCTAssertEqual([path.attribute unsignedIntegerValue], 0); + XCTAssertTrue([result[@"data"] isKindOfClass:[NSDictionary class]]); + XCTAssertTrue([result[@"data"][@"type"] isEqualToString:@"Boolean"]); + initialOnOffState = [result[@"data"][@"value"] boolValue]; + + [initialOnOffReportExpectation fulfill]; + }; // Subscribe XCTestExpectation * subscribeExpectation = [self expectationWithDescription:@"subscribe OnOff attribute"]; - __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(2) maxInterval:@(10)]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(0) maxInterval:@(10)]; [device subscribeToAttributesWithEndpointID:@1 clusterID:@6 attributeID:@0 @@ -1414,11 +1435,11 @@ - (void)test012_SubscribeKeepingPreviousSubscription [subscribeExpectation fulfill]; }]; - [self waitForExpectations:@[ subscribeExpectation ] timeout:kTimeoutInSeconds]; + [self waitForExpectations:@[ subscribeExpectation, initialOnOffReportExpectation ] timeout:kTimeoutInSeconds]; // Setup 2nd subscriber subscribeExpectation = [self expectationWithDescription:@"subscribe CurrentLevel attribute"]; - MTRSubscribeParams * myParams = [[MTRSubscribeParams alloc] initWithMinInterval:@(2) maxInterval:@(10)]; + MTRSubscribeParams * myParams = [[MTRSubscribeParams alloc] initWithMinInterval:@(0) maxInterval:@(10)]; myParams.replaceExistingSubscriptions = NO; [device subscribeToAttributesWithEndpointID:@1 clusterID:@8 @@ -1443,7 +1464,31 @@ - (void)test012_SubscribeKeepingPreviousSubscription // Wait till establishment [self waitForExpectations:@[ subscribeExpectation ] timeout:kTimeoutInSeconds]; - // Send command to clear attribute state + // If we were initially on, set up expectations for report that we have been + // turned off, so we make sure that comes through before we do the rest of + // the test. + XCTestExpectation * offReportExpectation; + if (initialOnOffState == YES) { + offReportExpectation = [self expectationWithDescription:@"OnOff attribute has become false."]; + firstReportHandler = ^(id _Nullable values, NSError * _Nullable error) { + XCTAssertNil(error); + + { + XCTAssertTrue([values isKindOfClass:[NSArray class]]); + NSDictionary * result = values[0]; + MTRAttributePath * path = result[@"attributePath"]; + XCTAssertEqual([path.endpoint unsignedIntegerValue], 1); + XCTAssertEqual([path.cluster unsignedIntegerValue], 6); + XCTAssertEqual([path.attribute unsignedIntegerValue], 0); + XCTAssertTrue([result[@"data"] isKindOfClass:[NSDictionary class]]); + XCTAssertTrue([result[@"data"][@"type"] isEqualToString:@"Boolean"]); + XCTAssertEqual([result[@"data"][@"value"] boolValue], NO); + } + [offReportExpectation fulfill]; + }; + } + + // Ensure that we are in the "off" state. XCTestExpectation * clearCommandExpectation = [self expectationWithDescription:@"Clearing command invoked"]; [device invokeCommandWithEndpointID:@1 clusterID:@6 @@ -1452,7 +1497,7 @@ - (void)test012_SubscribeKeepingPreviousSubscription timedInvokeTimeout:nil queue:queue completion:^(id _Nullable values, NSError * _Nullable error) { - NSLog(@"invoke command: On values: %@, error: %@", values, error); + NSLog(@"invoke command: Off values: %@, error: %@", values, error); XCTAssertNil(error); @@ -1471,6 +1516,9 @@ - (void)test012_SubscribeKeepingPreviousSubscription [clearCommandExpectation fulfill]; }]; [self waitForExpectations:@[ clearCommandExpectation ] timeout:kTimeoutInSeconds]; + if (offReportExpectation) { + [self waitForExpectations:@[ offReportExpectation ] timeout:kTimeoutInSeconds]; + } // Set up expectations for report XCTestExpectation * reportExpectation = [self expectationWithDescription:@"The 1st subscriber received OnOff attribute report"]; @@ -1622,7 +1670,7 @@ - (void)test013_TimedWriteAttribute // subscribe, which should get the new value at the timeout expectation = [self expectationWithDescription:@"Subscribed"]; __block void (^reportHandler)(id _Nullable values, NSError * _Nullable error); - __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(2) maxInterval:@(10)]; + __auto_type * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(0) maxInterval:@(10)]; [device subscribeToAttributesWithEndpointID:@1 clusterID:@8 attributeID:@17 From 401f44a391d3fba3499fd1c10aef546abc8f15c7 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 23 Sep 2024 17:06:25 -0400 Subject: [PATCH 03/19] Move some APIs that are only used on MTRDeviceController_Concrete to that interface. (#35728) Now that MTRDeviceControllerFactory only works with MTRDeviceController_Concrete, we can move some APIs from MTRDeviceController_Internal to MTRDeviceController_Concrete. --- .../Framework/CHIP/MTRDeviceController.mm | 44 ------------------- .../CHIP/MTRDeviceController_Concrete.h | 25 +++++++++++ .../CHIP/MTRDeviceController_Internal.h | 25 ----------- 3 files changed, 25 insertions(+), 69 deletions(-) diff --git a/src/darwin/Framework/CHIP/MTRDeviceController.mm b/src/darwin/Framework/CHIP/MTRDeviceController.mm index e069ea79a990c8..18e49b5847792e 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceController.mm @@ -320,20 +320,6 @@ - (void)_controllerResumed // Subclass hook; nothing to do. } -- (BOOL)matchesPendingShutdownControllerWithOperationalCertificate:(nullable MTRCertificateDERBytes)operationalCertificate andRootCertificate:(nullable MTRCertificateDERBytes)rootCertificate -{ - // TODO: Once the factory knows it's dealing with MTRDeviceController_Concrete, this can be removed, and its - // declaration moved to MTRDeviceController_Concrete. - return NO; -} - -- (void)clearPendingShutdown -{ - // TODO: Once the factory knows it's dealing with MTRDeviceController_Concrete, this can be removed, and its - // declaration moved to MTRDeviceController_Concrete. - MTR_ABSTRACT_METHOD(); -} - - (void)shutdown { MTR_ABSTRACT_METHOD(); @@ -1085,36 +1071,6 @@ - (nullable NSNumber *)compressedFabricID return storedValue.has_value() ? @(storedValue.value()) : nil; } -- (CHIP_ERROR)isRunningOnFabric:(chip::FabricTable *)fabricTable - fabricIndex:(chip::FabricIndex)fabricIndex - isRunning:(BOOL *)isRunning -{ - assertChipStackLockedByCurrentThread(); - - if (![self isRunning]) { - *isRunning = NO; - return CHIP_NO_ERROR; - } - - const chip::FabricInfo * otherFabric = fabricTable->FindFabricWithIndex(fabricIndex); - if (!otherFabric) { - // Should not happen... - return CHIP_ERROR_INCORRECT_STATE; - } - - if (_cppCommissioner->GetFabricId() != otherFabric->GetFabricId()) { - *isRunning = NO; - return CHIP_NO_ERROR; - } - - chip::Crypto::P256PublicKey ourRootPublicKey, otherRootPublicKey; - ReturnErrorOnFailure(_cppCommissioner->GetRootPublicKey(ourRootPublicKey)); - ReturnErrorOnFailure(fabricTable->FetchRootPubkey(otherFabric->GetFabricIndex(), otherRootPublicKey)); - - *isRunning = (ourRootPublicKey.Matches(otherRootPublicKey)); - return CHIP_NO_ERROR; -} - - (void)invalidateCASESessionForNode:(chip::NodeId)nodeID; { auto block = ^{ diff --git a/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.h b/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.h index 42c4092cc2ada6..ea71f351c72377 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.h +++ b/src/darwin/Framework/CHIP/MTRDeviceController_Concrete.h @@ -70,6 +70,21 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)deinitFromFactory; +/** + * Check whether this controller is running on the given fabric, as represented + * by the provided FabricTable and fabric index. The provided fabric table may + * not be the same as the fabric table this controller is using. This method + * MUST be called from the Matter work queue. + * + * Might return failure, in which case we don't know whether it's running on the + * given fabric. Otherwise it will set *isRunning to the right boolean value. + * + * Only MTRDeviceControllerFactory should be calling this. + */ +- (CHIP_ERROR)isRunningOnFabric:(chip::FabricTable *)fabricTable + fabricIndex:(chip::FabricIndex)fabricIndex + isRunning:(BOOL *)isRunning; + /** * Takes an assertion to keep the controller running. If `-[MTRDeviceController shutdown]` is called while an assertion * is held, the shutdown will be honored only after all assertions are released. Invoking this method multiple times increases @@ -84,6 +99,16 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)removeRunAssertion; +/** + * This method returns TRUE if this controller matches the fabric reference and node ID as listed in the parameters. + */ +- (BOOL)matchesPendingShutdownControllerWithOperationalCertificate:(nullable MTRCertificateDERBytes)operationalCertificate andRootCertificate:(nullable MTRCertificateDERBytes)rootCertificate; + +/** + * Clear any pending shutdown request. + */ +- (void)clearPendingShutdown; + @end NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/MTRDeviceController_Internal.h b/src/darwin/Framework/CHIP/MTRDeviceController_Internal.h index 182eb609f06820..a052d527b89b86 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceController_Internal.h +++ b/src/darwin/Framework/CHIP/MTRDeviceController_Internal.h @@ -121,21 +121,6 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, retain, nullable) NSData * rootPublicKey; -/** - * Check whether this controller is running on the given fabric, as represented - * by the provided FabricTable and fabric index. The provided fabric table may - * not be the same as the fabric table this controller is using. This method - * MUST be called from the Matter work queue. - * - * Might return failure, in which case we don't know whether it's running on the - * given fabric. Otherwise it will set *isRunning to the right boolean value. - * - * Only MTRDeviceControllerFactory should be calling this. - */ -- (CHIP_ERROR)isRunningOnFabric:(chip::FabricTable *)fabricTable - fabricIndex:(chip::FabricIndex)fabricIndex - isRunning:(BOOL *)isRunning; - /** * Ensure we have a CASE session to the given node ID and then call the provided * connection callback. This may be called on any queue (including the Matter @@ -265,16 +250,6 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)directlyGetSessionForNode:(chip::NodeId)nodeID completion:(MTRInternalDeviceConnectionCallback)completion; -/** - * This method returns TRUE if this controller matches the fabric reference and node ID as listed in the parameters. - */ -- (BOOL)matchesPendingShutdownControllerWithOperationalCertificate:(nullable MTRCertificateDERBytes)operationalCertificate andRootCertificate:(nullable MTRCertificateDERBytes)rootCertificate; - -/** - * Clear any pending shutdown request. - */ -- (void)clearPendingShutdown; - @end /** From b77b99995f55a203f91b91747208a5bbfabd76ab Mon Sep 17 00:00:00 2001 From: Kenneth Fu <80622799+fuxiaoming-lumi@users.noreply.github.com> Date: Tue, 24 Sep 2024 05:08:01 +0800 Subject: [PATCH 04/19] [Silabs] Add more gn arg to configure NVM3. (#35717) Add two new gn arg(sl_nvm3_nvm_size and sl_nvm3_cache_size) to configure NVM3. Developers can analyze their storage needs to adjust these two parameters, which can effectively improve storage efficiency. Especially after https://github.com/project-chip/connectedhomeip/pull/35480, developers would like to adjust these configuration. --- third_party/silabs/efr32_sdk.gni | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/third_party/silabs/efr32_sdk.gni b/third_party/silabs/efr32_sdk.gni index 1d4472a8bd7cfd..9a29ad6a05aa04 100644 --- a/third_party/silabs/efr32_sdk.gni +++ b/third_party/silabs/efr32_sdk.gni @@ -39,6 +39,8 @@ declare_args() { enable_openthread_cli = !(use_rs9116 || use_wf200 || use_SiWx917) kvs_max_entries = 255 sl_nvm3_max_object_size = 4092 + sl_nvm3_nvm_size = 40960 + sl_nvm3_cache_size = 200 # Use Silabs factory data provider example. # Users can implement their own. @@ -424,7 +426,8 @@ template("efr32_sdk") { "__STARTUP_CLEAR_BSS", "HARD_FAULT_LOG_ENABLE", "CORTEXM3_EFM32_MICRO", - "NVM3_DEFAULT_NVM_SIZE=40960", + "NVM3_DEFAULT_CACHE_SIZE=${sl_nvm3_cache_size}", + "NVM3_DEFAULT_NVM_SIZE=${sl_nvm3_nvm_size}", "NVM3_DEFAULT_MAX_OBJECT_SIZE=${sl_nvm3_max_object_size}", "KVS_MAX_ENTRIES=${kvs_max_entries}", "CORTEXM3=1", From a51fa843c2cc588f044d6bbfd032461b2e9fa0c8 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 23 Sep 2024 17:18:16 -0400 Subject: [PATCH 05/19] Fix error handling in Darwin DNS-SD implementation to clean up properly. (#35725) We had several codepaths where we could create a service ref but then do some fallible operations before calling Add() on the context. If those failed, they would call Finalize() on the context, which would delete the context, but _not_ DNSServiceRefDeallocate() the service ref. The fix is to make sure that: 1) All cases where we create a service ref successfully immediately set it on the context. 2) All context deletion goes through MdnsContexts::Delete, so that we make sure to clean up the service ref if there is one. --- src/platform/Darwin/DnssdContexts.cpp | 28 ++++++++------------ src/platform/Darwin/DnssdImpl.cpp | 37 ++++++++++++++++++++------- src/platform/Darwin/DnssdImpl.h | 11 ++++++-- 3 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/platform/Darwin/DnssdContexts.cpp b/src/platform/Darwin/DnssdContexts.cpp index ff869911e98e48..9d293c089665e2 100644 --- a/src/platform/Darwin/DnssdContexts.cpp +++ b/src/platform/Darwin/DnssdContexts.cpp @@ -135,7 +135,8 @@ CHIP_ERROR GenericContext::FinalizeInternal(const char * errorStr, CHIP_ERROR er } else { - chip::Platform::Delete(this); + // Ensure that we clean up our service ref, if any, correctly. + MdnsContexts::GetInstance().Delete(this); } return err; @@ -161,33 +162,22 @@ MdnsContexts::~MdnsContexts() } } -CHIP_ERROR MdnsContexts::Add(GenericContext * context, DNSServiceRef sdRef) +CHIP_ERROR MdnsContexts::Add(GenericContext * context) { - VerifyOrReturnError(context != nullptr || sdRef != nullptr, CHIP_ERROR_INVALID_ARGUMENT); - - if (context == nullptr) - { - DNSServiceRefDeallocate(sdRef); - return CHIP_ERROR_INVALID_ARGUMENT; - } - - if (sdRef == nullptr) + VerifyOrReturnError(context != nullptr, CHIP_ERROR_INVALID_ARGUMENT); + if (!context->serviceRef) { - chip::Platform::Delete(context); + Delete(context); return CHIP_ERROR_INVALID_ARGUMENT; } - auto err = DNSServiceSetDispatchQueue(sdRef, chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue()); + auto err = DNSServiceSetDispatchQueue(context->serviceRef, chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue()); if (kDNSServiceErr_NoError != err) { - // We can't just use our Delete to deallocate the service ref here, - // because our context may not have its serviceRef set yet. - DNSServiceRefDeallocate(sdRef); - chip::Platform::Delete(context); + Delete(context); return Error::ToChipError(err); } - context->serviceRef = sdRef; mContexts.push_back(context); return CHIP_NO_ERROR; @@ -242,6 +232,8 @@ CHIP_ERROR MdnsContexts::RemoveAllOfType(ContextType type) return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND; } +// TODO: Perhaps this cleanup code should just move into ~GenericContext, and +// the places that call this method should just Platform::Delete() the context? void MdnsContexts::Delete(GenericContext * context) { if (context->serviceRef != nullptr) diff --git a/src/platform/Darwin/DnssdImpl.cpp b/src/platform/Darwin/DnssdImpl.cpp index 37406009cf0247..5cd3a2d6fbad3c 100644 --- a/src/platform/Darwin/DnssdImpl.cpp +++ b/src/platform/Darwin/DnssdImpl.cpp @@ -188,12 +188,17 @@ CHIP_ERROR Register(void * context, DnssdPublishCallback callback, uint32_t inte auto err = sdCtx->mHostNameRegistrar.Init(hostname, addressType, interfaceId); VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); - DNSServiceRef sdRef; - err = DNSServiceRegister(&sdRef, registerFlags, interfaceId, name, type, kLocalDot, hostname, htons(port), record.size(), - record.data(), OnRegister, sdCtx); - VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); + err = DNSServiceRegister(&sdCtx->serviceRef, registerFlags, interfaceId, name, type, kLocalDot, hostname, htons(port), + record.size(), record.data(), OnRegister, sdCtx); + if (err != kDNSServiceErr_NoError) + { + // Just in case DNSServiceCreateConnection put garbage in the outparam + // on failure. + sdCtx->serviceRef = nullptr; + return sdCtx->Finalize(err); + } - return MdnsContexts::GetInstance().Add(sdCtx, sdRef); + return MdnsContexts::GetInstance().Add(sdCtx); } static void OnBrowse(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceId, DNSServiceErrorType err, const char * name, @@ -216,16 +221,23 @@ CHIP_ERROR BrowseOnDomain(BrowseHandler * sdCtx, uint32_t interfaceId, const cha CHIP_ERROR Browse(BrowseHandler * sdCtx, uint32_t interfaceId, const char * type) { auto err = DNSServiceCreateConnection(&sdCtx->serviceRef); - VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); + if (err != kDNSServiceErr_NoError) + { + // Just in case DNSServiceCreateConnection put garbage in the outparam + // on failure. + sdCtx->serviceRef = nullptr; + return sdCtx->Finalize(err); + } // We will browse on both the local domain and the SRP domain. + // BrowseOnDomain guarantees it will Finalize() on failure. ChipLogProgress(Discovery, "Browsing for: %s on local domain", StringOrNullMarker(type)); ReturnErrorOnFailure(BrowseOnDomain(sdCtx, interfaceId, type, kLocalDot)); ChipLogProgress(Discovery, "Browsing for: %s on %s domain", StringOrNullMarker(type), kSRPDot); ReturnErrorOnFailure(BrowseOnDomain(sdCtx, interfaceId, type, kSRPDot)); - return MdnsContexts::GetInstance().Add(sdCtx, sdCtx->serviceRef); + return MdnsContexts::GetInstance().Add(sdCtx); } CHIP_ERROR Browse(void * context, DnssdBrowseCallback callback, uint32_t interfaceId, const char * type, @@ -380,10 +392,17 @@ static CHIP_ERROR Resolve(ResolveContext * sdCtx, uint32_t interfaceId, chip::In StringOrNullMarker(name), StringOrNullMarker(domain), interfaceId); auto err = DNSServiceCreateConnection(&sdCtx->serviceRef); - VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err)); + if (err != kDNSServiceErr_NoError) + { + // Just in case DNSServiceCreateConnection put garbage in the outparam + // on failure. + sdCtx->serviceRef = nullptr; + return sdCtx->Finalize(err); + } // If we have a single domain from a browse, we will use that for the Resolve. // Otherwise we will try to resolve using both the local domain and the SRP domain. + // ResolveWithContext guarantees it will Finalize() on failure. if (domain != nullptr) { ReturnErrorOnFailure(ResolveWithContext(sdCtx, interfaceId, type, name, domain, &sdCtx->resolveContextWithNonSRPType)); @@ -400,7 +419,7 @@ static CHIP_ERROR Resolve(ResolveContext * sdCtx, uint32_t interfaceId, chip::In sdCtx->shouldStartSRPTimerForResolve = true; } - auto retval = MdnsContexts::GetInstance().Add(sdCtx, sdCtx->serviceRef); + auto retval = MdnsContexts::GetInstance().Add(sdCtx); if (retval == CHIP_NO_ERROR) { (*(sdCtx->consumerCounter))++; diff --git a/src/platform/Darwin/DnssdImpl.h b/src/platform/Darwin/DnssdImpl.h index 23044070f52362..d4cd05fecfe20b 100644 --- a/src/platform/Darwin/DnssdImpl.h +++ b/src/platform/Darwin/DnssdImpl.h @@ -43,7 +43,13 @@ struct GenericContext { ContextType type; void * context; - DNSServiceRef serviceRef; + // When using a GenericContext, if a DNSServiceRef is created successfully + // API consumers must ensure that it gets set as serviceRef on the context + // immediately, before any other operations that might fail can happen. + // + // In all cases, once a context has been created, Finalize() must be called + // on it to clean it up properly. + DNSServiceRef serviceRef = nullptr; virtual ~GenericContext() {} @@ -69,7 +75,8 @@ class MdnsContexts ~MdnsContexts(); static MdnsContexts & GetInstance() { return sInstance.get(); } - CHIP_ERROR Add(GenericContext * context, DNSServiceRef sdRef); + // The context being added is expected to have a valid serviceRef. + CHIP_ERROR Add(GenericContext * context); CHIP_ERROR Remove(GenericContext * context); CHIP_ERROR RemoveAllOfType(ContextType type); CHIP_ERROR Has(GenericContext * context); From 6b99a99a762e58f0b07b6b3e4d0d4f1fbad39c22 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 23 Sep 2024 17:19:05 -0400 Subject: [PATCH 06/19] Switch to macos-14 for some of the Darwin runners. (#35727) macos-14 runners are ARM, and should be much faster than the macos-13 runners. The YAML tests are not passing on macos-14 for some reason (being sorted out in https://github.com/project-chip/connectedhomeip/pull/35704), but other workflows can be switched, which is what this does. --- .github/workflows/darwin.yaml | 4 ++-- .github/workflows/example-tv-casting-darwin.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/darwin.yaml b/.github/workflows/darwin.yaml index 9eeac9118ef9d3..fa9e6144497414 100644 --- a/.github/workflows/darwin.yaml +++ b/.github/workflows/darwin.yaml @@ -36,7 +36,7 @@ jobs: framework: name: Build framework if: github.actor != 'restyled-io[bot]' - runs-on: macos-13 + runs-on: macos-14 strategy: matrix: options: # We don't need a full matrix @@ -73,7 +73,7 @@ jobs: name: Run framework tests if: github.actor != 'restyled-io[bot]' needs: [framework] # serialize to avoid running to many parallel macos runners - runs-on: macos-13 + runs-on: macos-14 strategy: matrix: options: # We don't need a full matrix diff --git a/.github/workflows/example-tv-casting-darwin.yaml b/.github/workflows/example-tv-casting-darwin.yaml index d9d9ef8f37cee9..d8b7b7895e250e 100644 --- a/.github/workflows/example-tv-casting-darwin.yaml +++ b/.github/workflows/example-tv-casting-darwin.yaml @@ -36,7 +36,7 @@ jobs: tv-casting-bridge: name: Build TV Casting Bridge example if: github.actor != 'restyled-io[bot]' - runs-on: macos-13 + runs-on: macos-14 steps: - name: Checkout uses: actions/checkout@v4 From 1597be7bf723656bfdc1d8b84a4240773e9d1a03 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 23 Sep 2024 17:53:14 -0400 Subject: [PATCH 07/19] Change some more internal MTRDeviceControllerFactory APIs to use MTRDeviceController_Concrete. (#35730) These always return concrete controllers. getRunningControllers was already claiming the right signature in the implementation, just not the header. --- .../Framework/CHIP/MTRDeviceControllerFactory.mm | 8 ++++---- .../CHIP/MTRDeviceControllerFactory_Internal.h | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm b/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm index 68f57a6954cc34..4cff8a633105b2 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerFactory.mm @@ -975,9 +975,9 @@ - (void)controllerShuttingDown:(MTRDeviceController_Concrete *)controller return [_controllers copy]; } -- (nullable MTRDeviceController *)runningControllerForFabricIndex:(FabricIndex)fabricIndex - includeControllerStartingUp:(BOOL)includeControllerStartingUp - includeControllerShuttingDown:(BOOL)includeControllerShuttingDown +- (nullable MTRDeviceController_Concrete *)runningControllerForFabricIndex:(FabricIndex)fabricIndex + includeControllerStartingUp:(BOOL)includeControllerStartingUp + includeControllerShuttingDown:(BOOL)includeControllerShuttingDown { assertChipStackLockedByCurrentThread(); @@ -1006,7 +1006,7 @@ - (nullable MTRDeviceController *)runningControllerForFabricIndex:(FabricIndex)f return nil; } -- (nullable MTRDeviceController *)runningControllerForFabricIndex:(chip::FabricIndex)fabricIndex +- (nullable MTRDeviceController_Concrete *)runningControllerForFabricIndex:(chip::FabricIndex)fabricIndex { return [self runningControllerForFabricIndex:fabricIndex includeControllerStartingUp:YES includeControllerShuttingDown:YES]; } diff --git a/src/darwin/Framework/CHIP/MTRDeviceControllerFactory_Internal.h b/src/darwin/Framework/CHIP/MTRDeviceControllerFactory_Internal.h index 46bb7819ad43f1..1642641717cbe8 100644 --- a/src/darwin/Framework/CHIP/MTRDeviceControllerFactory_Internal.h +++ b/src/darwin/Framework/CHIP/MTRDeviceControllerFactory_Internal.h @@ -57,21 +57,21 @@ MTR_DIRECT_MEMBERS * Get the list of running controllers. This will include controllers that are * in the middle of starting up or shutting down. */ -- (NSArray *)getRunningControllers; +- (NSArray *)getRunningControllers; /** * Find a running controller, if any, for the given fabric index. */ -- (nullable MTRDeviceController *)runningControllerForFabricIndex:(chip::FabricIndex)fabricIndex; +- (nullable MTRDeviceController_Concrete *)runningControllerForFabricIndex:(chip::FabricIndex)fabricIndex; /** * Find a running controller, if any, for the given fabric index. Allows * controlling whether to include a controller that is in the middle of startup * or shutdown. */ -- (nullable MTRDeviceController *)runningControllerForFabricIndex:(chip::FabricIndex)fabricIndex - includeControllerStartingUp:(BOOL)includeControllerStartingUp - includeControllerShuttingDown:(BOOL)includeControllerShuttingDown; +- (nullable MTRDeviceController_Concrete *)runningControllerForFabricIndex:(chip::FabricIndex)fabricIndex + includeControllerStartingUp:(BOOL)includeControllerStartingUp + includeControllerShuttingDown:(BOOL)includeControllerShuttingDown; /** * Notify the controller factory that a new operational instance with the given From 8bc3888e5c402b7e58d552328291b760de9100b6 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Mon, 23 Sep 2024 18:30:52 -0400 Subject: [PATCH 08/19] Removed attribute-type.h from attribute-metadata and moved definitions inside of .cpp file (#35731) --- src/app/util/attribute-metadata.cpp | 10 ++++++++++ src/app/util/attribute-metadata.h | 5 ++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/app/util/attribute-metadata.cpp b/src/app/util/attribute-metadata.cpp index bf649a93004a22..749ef16ca71558 100644 --- a/src/app/util/attribute-metadata.cpp +++ b/src/app/util/attribute-metadata.cpp @@ -18,6 +18,16 @@ #include +bool EmberAfAttributeMetadata::IsBoolean() const +{ + return attributeType == ZCL_BOOLEAN_ATTRIBUTE_TYPE; +} + +bool EmberAfAttributeMetadata::IsSignedIntegerAttribute() const +{ + return chip::app::IsSignedAttributeType(attributeType); +} + bool emberAfIsStringAttributeType(EmberAfAttributeType attributeType) { return (attributeType == ZCL_OCTET_STRING_ATTRIBUTE_TYPE || attributeType == ZCL_CHAR_STRING_ATTRIBUTE_TYPE); diff --git a/src/app/util/attribute-metadata.h b/src/app/util/attribute-metadata.h index 5be6916438d48a..6703e397d55934 100644 --- a/src/app/util/attribute-metadata.h +++ b/src/app/util/attribute-metadata.h @@ -17,7 +17,6 @@ #pragma once -#include #include #include @@ -161,12 +160,12 @@ struct EmberAfAttributeMetadata /** * Check wether this attribute is a boolean based on its type according to the spec. */ - bool IsBoolean() const { return attributeType == ZCL_BOOLEAN_ATTRIBUTE_TYPE; } + bool IsBoolean() const; /** * Check wether this attribute is signed based on its type according to the spec. */ - bool IsSignedIntegerAttribute() const { return chip::app::IsSignedAttributeType(attributeType); } + bool IsSignedIntegerAttribute() const; /** * Check whether this attribute has a define min and max. From b6daecb5186a9b0e87c209f11276dac911330ed7 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Mon, 23 Sep 2024 18:58:03 -0400 Subject: [PATCH 09/19] Pull request #11: Provisioning series 3 (#35733) Merge in WMN_TOOLS/matter_sdk from feature/provisioning_api_series3 to feature/rainier-ifc2 Squashed commit of the following: commit 0f219b792349f77756e33fe820fdb549376bb146 Author: lpbeliveau-silabs Date: Tue Sep 10 14:14:52 2024 -0400 Added series 3 API to replace MSC and updated to support series3 flash api --- .../provision/ProvisionStorageDefault.cpp | 49 ++++++++++++++++++- .../silabs/platformAbstraction/GsdkSpam.cpp | 2 +- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/examples/platform/silabs/provision/ProvisionStorageDefault.cpp b/examples/platform/silabs/provision/ProvisionStorageDefault.cpp index 801eb9e0b70c2e..6a889b5bffeb06 100644 --- a/examples/platform/silabs/provision/ProvisionStorageDefault.cpp +++ b/examples/platform/silabs/provision/ProvisionStorageDefault.cpp @@ -17,6 +17,7 @@ #include "AttestationKey.h" #include "ProvisionStorage.h" #include +#include #include #include #include @@ -34,7 +35,13 @@ #ifdef SLI_SI91X_MCU_INTERFACE #include #else +#ifdef _SILICON_LABS_32B_SERIES_2 #include +#elif defined(_SILICON_LABS_32B_SERIES_3) +#include "sl_se_manager.h" +#include "sl_se_manager_types.h" +#include +#endif // _SILICON_LABS_32B_SERIES_2 #include #endif @@ -44,6 +51,16 @@ extern void setNvm3End(uint32_t addr); #include #endif +#if defined(_SILICON_LABS_32B_SERIES_3) +// To remove any ambiguities regarding the Flash aliases, use the below macro to ignore the 8 MSB. +#define FLASH_GENERIC_MASK 0x00FFFFFF +#define GENERIC_ADDRESS(addr) ((addr) &FLASH_GENERIC_MASK) + +// Transforms any address into an address using the same alias as FLASH_BASE from the CMSIS. +#define CMSIS_CONVERTED_ADDRESS(addr) (GENERIC_ADDRESS(addr) | FLASH_BASE) +sl_se_command_context_t cmd_ctx; +#endif // _SILICON_LABS_32B_SERIES_3 + extern uint8_t linker_nvm_end[]; using namespace chip::Credentials; @@ -66,8 +83,18 @@ CHIP_ERROR ErasePage(uint32_t addr) { #ifdef SLI_SI91X_MCU_INTERFACE rsi_flash_erase_sector((uint32_t *) addr); -#else +#elif defined(_SILICON_LABS_32B_SERIES_2) MSC_ErasePage((uint32_t *) addr); +#elif defined(_SILICON_LABS_32B_SERIES_3) + sl_status_t status; + uint32_t * data_start = NULL; + size_t data_size; + + status = sl_se_data_region_get_location(&cmd_ctx, (void **) &data_start, &data_size); + VerifyOrReturnError(status == SL_STATUS_OK, CHIP_ERROR(status)); + VerifyOrReturnError(GENERIC_ADDRESS(addr) > GENERIC_ADDRESS((uint32_t) data_start), CHIP_ERROR_INVALID_ADDRESS); + status = sl_se_data_region_erase(&cmd_ctx, (void *) addr, 1); // Erase one page + VerifyOrReturnError(status == SL_STATUS_OK, CHIP_ERROR(status)); #endif return CHIP_NO_ERROR; } @@ -76,8 +103,18 @@ CHIP_ERROR WritePage(uint32_t addr, const uint8_t * data, size_t size) { #ifdef SLI_SI91X_MCU_INTERFACE rsi_flash_write((uint32_t *) addr, (unsigned char *) data, size); -#else +#elif defined(_SILICON_LABS_32B_SERIES_2) MSC_WriteWord((uint32_t *) addr, data, size); +#elif defined(_SILICON_LABS_32B_SERIES_3) + sl_status_t status; + uint32_t * data_start = NULL; + size_t data_size; + + status = sl_se_data_region_get_location(&cmd_ctx, (void **) &data_start, &data_size); + VerifyOrReturnError(status == SL_STATUS_OK, CHIP_ERROR(status)); + VerifyOrReturnError(GENERIC_ADDRESS(addr) > GENERIC_ADDRESS((uint32_t) data_start), CHIP_ERROR_INVALID_ADDRESS); + status = sl_se_data_region_write(&cmd_ctx, (void *) addr, data, size); + VerifyOrReturnError(status == SL_STATUS_OK, CHIP_ERROR(status)); #endif return CHIP_NO_ERROR; } @@ -161,7 +198,15 @@ CHIP_ERROR Storage::Initialize(uint32_t flash_addr, uint32_t flash_size) { #ifndef SLI_SI91X_MCU_INTERFACE base_addr = (flash_addr + flash_size - FLASH_PAGE_SIZE); + +#ifdef _SILICON_LABS_32B_SERIES_2 MSC_Init(); +#elif defined(_SILICON_LABS_32B_SERIES_3) + sl_status_t status; + status = sl_se_init(); + VerifyOrReturnError(status == SL_STATUS_OK, CHIP_ERROR_INTERNAL); + status = sl_se_init_command_context(&cmd_ctx); +#endif // _SILICON_LABS_32B_SERIES #endif // SLI_SI91X_MCU_INTERFACE #ifdef SL_PROVISION_GENERATOR setNvm3End(base_addr); diff --git a/src/platform/silabs/platformAbstraction/GsdkSpam.cpp b/src/platform/silabs/platformAbstraction/GsdkSpam.cpp index eb8704ecfc1116..92ddd281f8fe55 100644 --- a/src/platform/silabs/platformAbstraction/GsdkSpam.cpp +++ b/src/platform/silabs/platformAbstraction/GsdkSpam.cpp @@ -21,7 +21,7 @@ #include "em_rmu.h" #else #include "sl_hal_emu.h" -#endif +#endif // _SILICON_LABS_32B_SERIES_2 #include "sl_system_kernel.h" #ifdef ENABLE_WSTK_LEDS From 8f80f98642d58615d0996ae55bbd4d55e70af8a7 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 23 Sep 2024 19:08:15 -0400 Subject: [PATCH 10/19] Attempt to fix TSan issues in Swift unit tests. (#35736) The only reason we are messing with the delegate's fields is because we had no remove API, but we have that now. And maybe this will fix the claimed thread race between us setting its fields and it being destroyed. --- src/darwin/Framework/CHIPTests/MTRSwiftDeviceTests.swift | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/darwin/Framework/CHIPTests/MTRSwiftDeviceTests.swift b/src/darwin/Framework/CHIPTests/MTRSwiftDeviceTests.swift index e85ce0eeab0829..a9418821bb3209 100644 --- a/src/darwin/Framework/CHIPTests/MTRSwiftDeviceTests.swift +++ b/src/darwin/Framework/CHIPTests/MTRSwiftDeviceTests.swift @@ -414,12 +414,8 @@ class MTRSwiftDeviceTests : XCTestCase { wait(for: [ resubscriptionReachableExpectation, resubscriptionGotReportsExpectation ], timeout:60) - // Now make sure we ignore later tests. Ideally we would just unsubscribe - // or remove the delegate, but there's no good way to do that. - delegate.onReachable = { () -> Void in } - delegate.onNotReachable = nil - delegate.onAttributeDataReceived = nil - delegate.onEventDataReceived = nil + // Now make sure we ignore later tests. + device.remove(_: delegate) // Make sure we got no updated reports (because we had a cluster state cache // with data versions) during the resubscribe. From f6e34f41e235c3677155b6bda34c6c31e59956ad Mon Sep 17 00:00:00 2001 From: yunhanw-google Date: Mon, 23 Sep 2024 19:02:50 -0700 Subject: [PATCH 11/19] [SVE][ICD] Bump MaxICDMonitoringEntrySize to reasonable size (#35737) * Fix icd monitor entry size * Restyled by whitespace * Restyled by clang-format * port test from pr 35734 * update documentation * Update src/app/icd/server/ICDMonitoringTable.h Co-authored-by: Boris Zbarsky --------- Co-authored-by: Restyled.io Co-authored-by: Boris Zbarsky --- src/app/icd/server/ICDMonitoringTable.cpp | 1 + src/app/icd/server/ICDMonitoringTable.h | 17 +++++++++++++++-- .../icd/server/tests/TestICDMonitoringTable.cpp | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/app/icd/server/ICDMonitoringTable.cpp b/src/app/icd/server/ICDMonitoringTable.cpp index c5543c74125f52..a6adddde2e7404 100644 --- a/src/app/icd/server/ICDMonitoringTable.cpp +++ b/src/app/icd/server/ICDMonitoringTable.cpp @@ -53,6 +53,7 @@ CHIP_ERROR ICDMonitoringEntry::Serialize(TLV::TLVWriter & writer) const ReturnErrorOnFailure(writer.Put(TLV::ContextTag(Fields::kClientType), clientType)); ReturnErrorOnFailure(writer.EndContainer(outer)); + ReturnErrorOnFailure(writer.Finalize()); return CHIP_NO_ERROR; } diff --git a/src/app/icd/server/ICDMonitoringTable.h b/src/app/icd/server/ICDMonitoringTable.h index 942c56fda45e71..dca9fd21972341 100644 --- a/src/app/icd/server/ICDMonitoringTable.h +++ b/src/app/icd/server/ICDMonitoringTable.h @@ -34,11 +34,24 @@ using SymmetricKeystore = SessionKeystore; namespace chip { -inline constexpr size_t kICDMonitoringBufferSize = 60; +static constexpr size_t MaxICDMonitoringEntrySize() +{ + // All the fields added together + return TLV::EstimateStructOverhead(sizeof(NodeId) /*checkInNodeID*/, sizeof(uint64_t) /*monitoredSubject*/, + sizeof(Crypto::Symmetric128BitsKeyByteArray) /*aes_key_handle*/, + sizeof(Crypto::Symmetric128BitsKeyByteArray) /*hmac_key_handle*/, + sizeof(uint8_t) /*client_type*/) * + // Provide 50% extra space to make a firmware upgrade that starts storing + // more data followed by a downgrade work easily and reliably. + // The 50% number is chosen fairly randomly; storage increases larger than that are + // possible but need to be staged carefully. + 3 / 2; +} + +inline constexpr size_t kICDMonitoringBufferSize = MaxICDMonitoringEntrySize(); struct ICDMonitoringEntry : public PersistentData { - ICDMonitoringEntry(FabricIndex fabric = kUndefinedFabricIndex, NodeId nodeId = kUndefinedNodeId) { this->fabricIndex = fabric; diff --git a/src/app/icd/server/tests/TestICDMonitoringTable.cpp b/src/app/icd/server/tests/TestICDMonitoringTable.cpp index 177f8caba507e1..81fcb2af18a250 100644 --- a/src/app/icd/server/tests/TestICDMonitoringTable.cpp +++ b/src/app/icd/server/tests/TestICDMonitoringTable.cpp @@ -43,6 +43,8 @@ constexpr uint64_t kClientNodeId13 = 0x100003; constexpr uint64_t kClientNodeId21 = 0x200001; constexpr uint64_t kClientNodeId22 = 0x200002; +constexpr uint64_t kClientNodeMaxValue = std::numeric_limits::max(); + constexpr uint8_t kKeyBuffer0a[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; constexpr uint8_t kKeyBuffer0b[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -98,6 +100,20 @@ TEST(TestICDMonitoringTable, TestEntryAssignationOverload) EXPECT_TRUE(entry2.IsKeyEquivalent(ByteSpan(kKeyBuffer1a))); } +TEST(TestICDMonitoringTable, TestEntryMaximumSize) +{ + TestPersistentStorageDelegate storage; + TestSessionKeystoreImpl keystore; + ICDMonitoringTable table(storage, kTestFabricIndex1, kMaxTestClients1, &keystore); + + ICDMonitoringEntry entry(&keystore); + entry.checkInNodeID = kClientNodeMaxValue; + entry.monitoredSubject = kClientNodeMaxValue; + entry.clientType = ClientTypeEnum::kPermanent; + EXPECT_EQ(CHIP_NO_ERROR, entry.SetKey(ByteSpan(kKeyBuffer1a))); + EXPECT_EQ(CHIP_NO_ERROR, table.Set(0, entry)); +} + TEST(TestICDMonitoringTable, TestEntryKeyFunctions) { TestSessionKeystoreImpl keystore; From fbc0d2149aff325c910c0811da640cc3d25bd87b Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Mon, 23 Sep 2024 22:41:12 -0400 Subject: [PATCH 12/19] Update Darwin availability annotations. (#35738) --- .../CHIP/templates/availability.yaml | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/darwin/Framework/CHIP/templates/availability.yaml b/src/darwin/Framework/CHIP/templates/availability.yaml index a8d32569d1aa92..12458cdaec950d 100644 --- a/src/darwin/Framework/CHIP/templates/availability.yaml +++ b/src/darwin/Framework/CHIP/templates/availability.yaml @@ -9778,6 +9778,8 @@ - GlobalStruct - NullableGlobalEnum - NullableGlobalStruct + - ReadFailureCode + - FailureInt32U commands: AccessControl: # Targeting 1.4 @@ -9862,6 +9864,44 @@ - RequiredTCNotAccepted - TCAcknowledgementsNotReceived - TCMinVersionNotMet + RVCCleanMode: + # Not clear whether these will stay in the XML + ModeTag: + - Auto + - Quick + - Quiet + - LowNoise + - LowEnergy + - Min + - Max + - Night + - Day + - Vacation + RVCOperationalState: + # Not clear whether these will stay in the XML + ErrorStateEnum: + - NoError + - UnableToStartOrResume + - UnableToCompleteOperation + - CommandInvalidInState + OperationalStateEnum: + - Stopped + - Running + - Paused + - Error + RVCRunMode: + # Not clear whether these will stay in the XML + ModeTag: + - Auto + - Quick + - Quiet + - LowNoise + - LowEnergy + - Min + - Max + - Night + - Day + - Vacation bitmaps: AccessControl: # Targeting 1.4 From 83de9cac4202453a2c94b2a0f3f5cd991ff74f2d Mon Sep 17 00:00:00 2001 From: Martin Girardot <165289184+Martin-NXP@users.noreply.github.com> Date: Tue, 24 Sep 2024 15:06:23 +0200 Subject: [PATCH 13/19] [NXP] Add TBRM and wifi connect support (#35646) * [NXP] Update ot-nxp submodule Signed-off-by: Martin Girardot * [NXP][third_party] Enable lwip and ephemeral key CLI addons Signed-off-by: Martin Girardot * [NXP][examples] Add support for TBR management cluster and secondary nwk, Updated common app to work with SNI and TBRM Signed-off-by: Martin Girardot * [NXP][src] Add support for TBR management cluster and secondary nwk, Updated common app to work with SNI and TBRM Signed-off-by: Martin Girardot * [NXP][workflows] Only thermostat app support OTBR feature Signed-off-by: Martin Girardot * [NXP][doc] add OTBR guide Signed-off-by: Martin Girardot * [NXP][platform][rw61x] Add support of boot reason Signed-off-by: Martin Girardot (cherry picked from commit d8f44419ea89d5ecec73fe8d82fdb30d444f49b3) * [NXP] Adding wifi_connect module Signed-off-by: Martin Girardot * [NXP] setup_discriminator argument value was only applied when OTA requestor enabled (cherry picked from commit fa9de443e3129ecf7befb4404fb2dd0efc213a29) * Restyled by gn * Restyled by prettier-markdown * [NXP] Regenerate .zap and .matter file for BR Signed-off-by: Martin Girardot * [NXP] Fix spelling issue Signed-off-by: Martin Girardot * Restyled by prettier-markdown * [NXP] Fix spelling issue Signed-off-by: Martin Girardot * [NXP] Fix otbr build issue Signed-off-by: Martin Girardot * Restyled by gn * [NXP] Disable identify cluster on endpoint 0 Signed-off-by: Martin Girardot --------- Signed-off-by: Martin Girardot Co-authored-by: Restyled.io --- .github/.wordlist.txt | 1 + .github/workflows/examples-nxp.yaml | 2 - docs/guides/nxp/nxp_otbr_guide.md | 107 + .../all-clusters-app/nxp/rt/rw61x/BUILD.gn | 54 +- .../all-clusters-app/nxp/rt/rw61x/README.md | 35 +- .../laundry-washer-app/nxp/rt/rw61x/BUILD.gn | 54 +- .../nxp/common/app_task/include/AppTaskBase.h | 11 + .../common/app_task/source/AppTaskBase.cpp | 49 +- .../include/CommonDeviceCallbacks.h | 2 +- .../source/CommonDeviceCallbacks.cpp | 23 +- .../common/wifi_connect/include/WifiConnect.h | 42 + .../wifi_connect/source/WifiConnect.cpp | 53 + examples/thermostat/nxp/rt/rw61x/BUILD.gn | 69 +- examples/thermostat/nxp/zap/BUILD.gn | 5 +- .../nxp/zap/thermostat_matter_br.matter | 2766 +++++++++ .../nxp/zap/thermostat_matter_br.zap | 5392 +++++++++++++++++ .../nxp/common/ConnectivityManagerImpl.cpp | 9 +- src/platform/nxp/common/DnssdImpl.cpp | 897 +-- src/platform/nxp/common/DnssdImplBr.cpp | 939 +++ src/platform/nxp/common/DnssdImplBr.h | 46 + src/platform/nxp/rt/rw61x/BUILD.gn | 33 +- .../nxp/rt/rw61x/PlatformManagerImpl.cpp | 1 + src/platform/nxp/rt/rw61x/args.gni | 2 + third_party/openthread/ot-nxp | 2 +- .../platforms/nxp/rt/rw61x/BUILD.gn | 20 + 25 files changed, 9604 insertions(+), 1010 deletions(-) create mode 100644 docs/guides/nxp/nxp_otbr_guide.md create mode 100644 examples/platform/nxp/common/wifi_connect/include/WifiConnect.h create mode 100644 examples/platform/nxp/common/wifi_connect/source/WifiConnect.cpp create mode 100644 examples/thermostat/nxp/zap/thermostat_matter_br.matter create mode 100644 examples/thermostat/nxp/zap/thermostat_matter_br.zap create mode 100644 src/platform/nxp/common/DnssdImplBr.cpp create mode 100644 src/platform/nxp/common/DnssdImplBr.h diff --git a/.github/.wordlist.txt b/.github/.wordlist.txt index 9467074fdbcfd4..dc56ae93a28e1d 100644 --- a/.github/.wordlist.txt +++ b/.github/.wordlist.txt @@ -1630,3 +1630,4 @@ Zigbee zigbeealliance zigbeethread zsdk +TBR diff --git a/.github/workflows/examples-nxp.yaml b/.github/workflows/examples-nxp.yaml index fc929eff2601c0..e8e335997db24d 100644 --- a/.github/workflows/examples-nxp.yaml +++ b/.github/workflows/examples-nxp.yaml @@ -242,7 +242,6 @@ jobs: ./scripts/build/build_examples.py \ --target nxp-rw61x-freertos-all-clusters-wifi \ --target nxp-rw61x-freertos-all-clusters-thread \ - --target nxp-rw61x-freertos-all-clusters-thread-wifi \ --target nxp-rw61x-freertos-all-clusters-wifi-ota-cmake \ build \ --copy-artifacts-to out/artifacts \ @@ -265,7 +264,6 @@ jobs: ./scripts/build/build_examples.py \ --target nxp-rw61x-freertos-laundry-washer-wifi \ --target nxp-rw61x-freertos-laundry-washer-thread \ - --target nxp-rw61x-freertos-laundry-washer-thread-wifi \ build \ --copy-artifacts-to out/artifacts \ " diff --git a/docs/guides/nxp/nxp_otbr_guide.md b/docs/guides/nxp/nxp_otbr_guide.md new file mode 100644 index 00000000000000..fd993f02e5376a --- /dev/null +++ b/docs/guides/nxp/nxp_otbr_guide.md @@ -0,0 +1,107 @@ +# Thread Border Router usage + +This document describes the use of the Thread Border router and secondary +network interface for a Matter application + +
+ +- [Thread Border Router usage](#thread-border-router-usage) + - [Thread Border Router overview](#thread-border-router-overview) + - [Using the Thread Border Router management cluster](#using-the-thread-border-router-management-cluster) + - [Using the Secondary Network commissioning interface](#using-the-secondary-network-commissioning-interface) + - [Using the Thread credential sharing mechanism](#using-the-thread-credential-sharing-mechanism) + +
+ + + +## Thread Border Router overview + +This section contains an overview of the Border Router architecture and +describes the general use cases. + + + +## Using the Thread Border Router management cluster + +The Thread Border Router management cluster allows provisioning of the Thread +interface using a Matter commissioner. + +After the device has been provisioned over WIFI the set active dataset command +can be used to configure the Thread active dataset on the border router. Once +the dataset is set successfully the Thread network interface will be enabled and +the device will create a new PAN or join an existing one if already present. +Note that this command cannot be used on a device that already has an active +dataset configured. In this situation the set pending dataset command must be +used instead. + +Before using the set active dataset command a fail-safe timer must be armed +(recommend using a timeout of 120 seconds): + +``` +ubuntu@ubuntu:~$ ./chip-tool generalcommissioning arm-fail-safe timeout-seconds 1 node-id 0 +``` + +Then an active dataset in HEX TLV format (the same type used to provision a +Matter over Thread device using the `ble-thread` command) can be used to +provision the Border Router. What the active dataset should be is outside the +scope of this README but as an example one can be obtained from the OpenThread +cli on an already provisioned device using the `dataset active -x` command. + +Note that the Thread Border Router management cluster has been set to endpoint 2 +in the zap file. + +``` +ubuntu@ubuntu:~$ ./chip-tool threadborderroutermanagement set-active-dataset-request hex: node id 2 +``` + +If the active dataset command is successful, a commissioning complete command +must be send to disarm the fail-safe timer and commit the configuration to +non-volatile storage. + +``` +ubuntu@ubuntu:~$ ./chip-tool-19-jul generalcommissioning commissioning-complete node-id 0 +``` + +Note that this command cannot be used on a device that already has an active +dataset configured. In this situation the set pending dataset command must be +used instead. + +``` +ubuntu@ubuntu:~$ ./chip-tool threadborderroutermanagement set-pending-dataset-request hex: node id 2 +``` + +To read the active dataset of an already provisioned device, for example to make +a joining Border Router use the same Thread network as an already configured +one, the get active dataset command can be used: + +``` +ubuntu@ubuntu:~$ ./chip-tool-19-jul threadborderroutermanagement get-active-dataset-request node-id 2 +``` + + + +## Using the Secondary Network commissioning interface + +To use the secondary network commissioning interface over Thread the device must +not be provisioned over WIFI. The regular `ble-thread` pairing is used as for +any other Matter over Thread device. The chip-tool will read all the endpoints +of the device and discover Thread network commissioning cluster on endpoint 3 +and use that to provision the device. As for any other Matter over Thread device +a Thread Border Router is required in this case. + +``` +ubuntu@ubuntu:~$ ./chip-tool pairing ble-thread node-id hex: 20202021 3840 +``` + + + +## Using the Thread credential sharing mechanism + +The details about using the credential sharing mechanism are in the ot-nxp repo +border router application +[readme](https://github.com/NXP/ot-nxp/blob/v1.4.0-pvw1/examples/br/README-OTBR.md). +See `Ephemeral Key functionality` section. + +Note that all OpenThread commands executed from then Matter CLI must have +`otcli` added before the command. diff --git a/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn b/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn index b0e1c1c47a98ea..bdc878cc0f5250 100644 --- a/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn +++ b/examples/all-clusters-app/nxp/rt/rw61x/BUILD.gn @@ -35,15 +35,10 @@ assert(target_os == "freertos") assert(nxp_platform == "rt/rw61x") declare_args() { - # Allows to start the tcp download test app - tcp_download = false - - # Allows to start the wifi connect test app - wifi_connect = false - - # The 2 params below are used only if tcp_download or wifi_connect are true, otherwise they're unused. - wifi_ssid = "" - wifi_password = "" + # Allows to connect to a predefine Wi-Fi network at boot + wifi_auto_connect_at_boot = false + wifi_auto_connect_at_boot_ssid = "" + wifi_auto_connect_at_boot_password = "" # Setup discriminator as argument setup_discriminator = 3840 @@ -53,10 +48,6 @@ example_platform_dir = "${nxp_sdk_matter_support_root}/examples/platform/${nxp_platform}" common_example_dir = "${chip_root}/examples/platform/nxp/common" -if (tcp_download == true && wifi_connect == true) { - assert("Cannot enable tcp_download and wifi_connect at the same time!") -} - app_common_folder = "all-clusters-app/all-clusters-common" # Create here the SDK instance. @@ -213,42 +204,21 @@ rt_executable("all_cluster_app") { ] } - if (wifi_connect) { + if (wifi_auto_connect_at_boot) { + assert(wifi_auto_connect_at_boot_ssid != "" && + wifi_auto_connect_at_boot_password != "", + "WiFi SSID and password must be specified at build time!") + defines += [ - "WIFI_CONNECT_TASK=1", - "WIFI_CONNECT=1", + "CONFIG_CHIP_APP_WIFI_CONNECT_AT_BOOT=1", + "CONFIG_CHIP_APP_WIFI_SSID=\"${wifi_auto_connect_at_boot_ssid}\"", + "CONFIG_CHIP_APP_WIFI_PASSWORD=\"${wifi_auto_connect_at_boot_password}\"", ] - if (!chip_enable_matter_cli) { - assert(wifi_ssid != "" && wifi_password != "", - "WiFi SSID and password must be specified at build time!") - } - - if (wifi_ssid != "") { - defines += [ "WIFI_SSID=\"${wifi_ssid}\"" ] - } - - if (wifi_password != "") { - defines += [ "WIFI_PASSWORD=\"${wifi_password}\"" ] - } - include_dirs += [ "${common_example_dir}/wifi_connect/include" ] sources += [ "${common_example_dir}/wifi_connect/source/WifiConnect.cpp" ] } - if (tcp_download) { - defines += [ "CONFIG_CHIP_TCP_DOWNLOAD=1" ] - defines += [ - "WIFI_CONNECT=1", - "WIFI_SSID=\"${wifi_ssid}\"", - "WIFI_PASSWORD=\"${wifi_password}\"", - ] - - include_dirs += [ "${common_example_dir}/tcp_download_test/include" ] - sources += - [ "${common_example_dir}/tcp_download_test/source/TcpDownload.cpp" ] - } - # In case a dedicated assert function needs to be supported the flag sdk_fsl_assert_support should be set to false # The would add to the build a dedicated application assert implementation. if (!sdk_fsl_assert_support) { diff --git a/examples/all-clusters-app/nxp/rt/rw61x/README.md b/examples/all-clusters-app/nxp/rt/rw61x/README.md index 9356e4b8fe3617..61d3f008697a58 100644 --- a/examples/all-clusters-app/nxp/rt/rw61x/README.md +++ b/examples/all-clusters-app/nxp/rt/rw61x/README.md @@ -16,6 +16,7 @@ commissioning and different cluster control. - [Testing the example](#testing-the-example) - [Matter Shell](#testing-the-all-clusters-application-with-matter-cli-enabled) - [OTA Software Update](#ota-software-update) +- [Thread Border Router overview](#thread-border-router-overview)
@@ -124,8 +125,13 @@ user@ubuntu:~/Desktop/git/connectedhomeip/examples/all-clusters-app/nxp/rt/rw61x #### Building with Matter over Wifi + OpenThread Border Router configuration on RW612 -This configuration requires enabling the Matter CLI in order to control the -Thread network on the Border Router. +This configuration supports the Thread Border Router management cluster to +provision the Thread credentials. Enabling the Matter CLI in order to control +the Thread network on the Border Router is optional but recommended for other +features like the Thread credential sharing. + +Note that the Thread Border Router management cluster is only supported on the +thermostat application for now. - Build Matter with Border Router configuration with BLE commissioning (ble-wifi) : @@ -142,6 +148,13 @@ out/debug/chip-rw61x-all-cluster-example. Optional GN options that can be added when building an application: +- To enable the + [secondary network commissioning interface](../../../../../docs/guides/nxp/nxp_otbr_guide.md#using-the-secondary-network-commissioning-interface), + the arguments `chip_enable_secondary_nwk_if=true` and + `chip_device_config_thread_network_endpoint_id=2` must be added to the _gn + gen_ command. Note that this is only supported when building the Matter over + Wifi + OpenThread Border Router configuration. Note that is only supported + on the on the thermostat application for now. - To enable the [matter CLI](README.md#testing-the-all-clusters-application-with-matter-cli-enabled), the argument `chip_enable_matter_cli=true` must be added to the _gn gen_ @@ -265,9 +278,11 @@ The "ble-thread" pairing method can be used in order to commission the device. #### Matter over wifi with openthread border router configuration : -In order to create or join a Thread network on the Matter Border Router, the -`otcli` commands from the matter CLI can be used. For more information about -using the matter shell, follow instructions from +In order to create or join a Thread network on the Matter Border Router, the TBR +management cluster or the `otcli` commands from the matter CLI can be used. For +more information about using the TBR management cluster follow instructions from +['Using the TBR management cluster'](../../../../../docs/guides/nxp/nxp_otbr_guide.md#using-the-thread-border-router-management-cluster). +For more information about using the matter shell, follow instructions from ['Testing the all-clusters application with Matter CLI'](#testing-the-all-clusters-application-with-matter-cli-enabled). In this configuration, the device can be commissioned over Wi-Fi with the @@ -393,3 +408,13 @@ Over-The-Air software updates are supported with the RW61x all-clusters example. The process to follow in order to perform a software update is described in the dedicated guide ['Matter Over-The-Air Software Update with NXP RW61x example applications'](../../../../../docs/guides/nxp/nxp_rw61x_ota_software_update.md). + + + +## Thread Border Router overview + +To enable Thread Border Router support see the [build](README.md#building) +section. + +The complete Border Router guide is located +[here](../../../../../docs/guides/nxp/nxp_otbr_guide.md). diff --git a/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn b/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn index 580a3ad556702b..cb0b7ba0a96439 100644 --- a/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn +++ b/examples/laundry-washer-app/nxp/rt/rw61x/BUILD.gn @@ -35,15 +35,10 @@ assert(target_os == "freertos") assert(nxp_platform == "rt/rw61x") declare_args() { - # Allows to start the tcp download test app - tcp_download = false - - # Allows to start the wifi connect test app - wifi_connect = false - - # The 2 params below are used only if tcp_download or wifi_connect are true, otherwise they're unused. - wifi_ssid = "" - wifi_password = "" + # Allows to connect to a predefine Wi-Fi network at boot + wifi_auto_connect_at_boot = false + wifi_auto_connect_at_boot_ssid = "" + wifi_auto_connect_at_boot_password = "" # Setup discriminator as argument setup_discriminator = 3840 @@ -53,10 +48,6 @@ example_platform_dir = "${nxp_sdk_matter_support_root}/examples/platform/${nxp_platform}" common_example_dir = "${chip_root}/examples/platform/nxp/common" -if (tcp_download == true && wifi_connect == true) { - assert("Cannot enable tcp_download and wifi_connect at the same time!") -} - # Use NXP custom zap files for laundry-washer device-type app_common_folder = "laundry-washer-app/nxp/zap" @@ -218,42 +209,21 @@ rt_executable("laundry-washer") { ] } - if (wifi_connect) { + if (wifi_auto_connect_at_boot) { + assert(wifi_auto_connect_at_boot_ssid != "" && + wifi_auto_connect_at_boot_password != "", + "WiFi SSID and password must be specified at build time!") + defines += [ - "WIFI_CONNECT_TASK=1", - "WIFI_CONNECT=1", + "CONFIG_CHIP_APP_WIFI_CONNECT_AT_BOOT=1", + "CONFIG_CHIP_APP_WIFI_SSID=\"${wifi_auto_connect_at_boot_ssid}\"", + "CONFIG_CHIP_APP_WIFI_PASSWORD=\"${wifi_auto_connect_at_boot_password}\"", ] - if (!chip_enable_matter_cli) { - assert(wifi_ssid != "" && wifi_password != "", - "WiFi SSID and password must be specified at build time!") - } - - if (wifi_ssid != "") { - defines += [ "WIFI_SSID=\"${wifi_ssid}\"" ] - } - - if (wifi_password != "") { - defines += [ "WIFI_PASSWORD=\"${wifi_password}\"" ] - } - include_dirs += [ "${common_example_dir}/wifi_connect/include" ] sources += [ "${common_example_dir}/wifi_connect/source/WifiConnect.cpp" ] } - if (tcp_download) { - defines += [ "CONFIG_CHIP_TCP_DOWNLOAD=1" ] - defines += [ - "WIFI_CONNECT=1", - "WIFI_SSID=\"${wifi_ssid}\"", - "WIFI_PASSWORD=\"${wifi_password}\"", - ] - - include_dirs += [ "${common_example_dir}/tcp_download_test/include" ] - sources += - [ "${common_example_dir}/tcp_download_test/source/TcpDownload.cpp" ] - } - # In case a dedicated assert function needs to be supported the flag sdk_fsl_assert_support should be set to false # The would add to the build a dedicated application assert implementation. if (!sdk_fsl_assert_support) { diff --git a/examples/platform/nxp/common/app_task/include/AppTaskBase.h b/examples/platform/nxp/common/app_task/include/AppTaskBase.h index 38770fa0e5ec26..ab29af27c29561 100644 --- a/examples/platform/nxp/common/app_task/include/AppTaskBase.h +++ b/examples/platform/nxp/common/app_task/include/AppTaskBase.h @@ -169,6 +169,17 @@ class AppTaskBase */ static void InitServer(intptr_t arg); +#if CHIP_DEVICE_CONFIG_ENABLE_TBR + /** + * \brief Initialize the Thread Border Router management cluster. + * + * Called when the border router function is up and running. This cluster stays disabled + * when the application is used as a Matter over Thread device. + * + */ + void EnableTbrManagementCluster(); +#endif + /** * Commissioning handlers * Generic implementation is provided within this class diff --git a/examples/platform/nxp/common/app_task/source/AppTaskBase.cpp b/examples/platform/nxp/common/app_task/source/AppTaskBase.cpp index c62be98d22c9b1..2646ffca4ef26d 100644 --- a/examples/platform/nxp/common/app_task/source/AppTaskBase.cpp +++ b/examples/platform/nxp/common/app_task/source/AppTaskBase.cpp @@ -30,6 +30,7 @@ #include #include + #include #include "lib/core/ErrorStr.h" @@ -56,8 +57,8 @@ #include #endif -#if CONFIG_CHIP_TCP_DOWNLOAD -#include "TcpDownload.h" +#if CONFIG_CHIP_APP_WIFI_CONNECT_AT_BOOT +#include "WifiConnect.h" #endif #if CONFIG_OPERATIONAL_KEYSTORE @@ -97,6 +98,11 @@ #include #endif +#if CHIP_DEVICE_CONFIG_ENABLE_TBR +#include "platform/OpenThread/GenericThreadBorderRouterDelegate.h" +#include +#endif + #ifndef CONFIG_THREAD_DEVICE_TYPE #define CONFIG_THREAD_DEVICE_TYPE kThreadDeviceType_Router #endif @@ -120,12 +126,23 @@ app::Clusters::NetworkCommissioning::Instance sNetworkCommissioningInstance(0, chip::NXP::App::GetAppTask().GetEthernetDriverInstance()); #endif +#if CHIP_DEVICE_CONFIG_ENABLE_TBR +static constexpr EndpointId kThreadBRMgmtEndpoint = 2; +static CharSpan sBrName("NXP-BR", strlen("NXP-BR")); +#endif + #if CHIP_CONFIG_ENABLE_ICD_SERVER || (CONFIG_CHIP_TEST_EVENT && CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR) static uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; #endif +#ifdef SMOKE_CO_ALARM +static uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, + 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, + 0xcc, 0xdd, 0xee, 0xff }; +#endif + #if CONFIG_NET_L2_OPENTHREAD void LockOpenThreadTask(void) { @@ -197,6 +214,14 @@ void chip::NXP::App::AppTaskBase::InitServer(intptr_t arg) #if CONFIG_CHIP_OTA_PROVIDER InitOTAServer(); #endif + +#if CONFIG_CHIP_APP_WIFI_CONNECT_AT_BOOT + VerifyOrDie(WifiConnectAtboot(chip::NXP::App::GetAppTask().GetWifiDriverInstance()) == CHIP_NO_ERROR); +#endif + +#if CHIP_DEVICE_CONFIG_ENABLE_TBR + GetAppTask().EnableTbrManagementCluster(); +#endif } CHIP_ERROR chip::NXP::App::AppTaskBase::Init() @@ -326,10 +351,6 @@ CHIP_ERROR chip::NXP::App::AppTaskBase::Init() } #endif -#if CONFIG_CHIP_TCP_DOWNLOAD - EnableTcpDownloadComponent(); -#endif - exit: return err; } @@ -443,3 +464,19 @@ void chip::NXP::App::AppTaskBase::PrintCurrentVersion() ChipLogProgress(DeviceLayer, "Current Software Version: %s, %d", currentSoftwareVer, static_cast(currentVersion)); } + +#if CHIP_DEVICE_CONFIG_ENABLE_TBR +void chip::NXP::App::AppTaskBase::EnableTbrManagementCluster() +{ + auto * persistentStorage = &Server::GetInstance().GetPersistentStorage(); + + static ThreadBorderRouterManagement::GenericOpenThreadBorderRouterDelegate sThreadBRDelegate(persistentStorage); + static ThreadBorderRouterManagement::ServerInstance sThreadBRMgmtInstance(kThreadBRMgmtEndpoint, &sThreadBRDelegate, + Server::GetInstance().GetFailSafeContext()); + + // Initialize TBR name + sThreadBRDelegate.SetThreadBorderRouterName(sBrName); + // Initialize TBR cluster + sThreadBRMgmtInstance.Init(); +} +#endif diff --git a/examples/platform/nxp/common/device_callbacks/include/CommonDeviceCallbacks.h b/examples/platform/nxp/common/device_callbacks/include/CommonDeviceCallbacks.h index 4cbd5028ce58b3..fc8b2ed1774b93 100644 --- a/examples/platform/nxp/common/device_callbacks/include/CommonDeviceCallbacks.h +++ b/examples/platform/nxp/common/device_callbacks/include/CommonDeviceCallbacks.h @@ -40,7 +40,7 @@ class CommonDeviceCallbacks : public chip::DeviceManager::CHIPDeviceManagerCallb virtual void OnInternetConnectivityChange(const chip::DeviceLayer::ChipDeviceEvent * event); virtual void OnSessionEstablished(const chip::DeviceLayer::ChipDeviceEvent * event); virtual void OnInterfaceIpAddressChanged(const chip::DeviceLayer::ChipDeviceEvent * event); -#if CHIP_ENABLE_OPENTHREAD && CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED +#if CHIP_ENABLE_OPENTHREAD virtual void OnComissioningComplete(const chip::DeviceLayer::ChipDeviceEvent * event); #endif }; diff --git a/examples/platform/nxp/common/device_callbacks/source/CommonDeviceCallbacks.cpp b/examples/platform/nxp/common/device_callbacks/source/CommonDeviceCallbacks.cpp index 2e40fdefb2e119..1bab4b09f58eda 100644 --- a/examples/platform/nxp/common/device_callbacks/source/CommonDeviceCallbacks.cpp +++ b/examples/platform/nxp/common/device_callbacks/source/CommonDeviceCallbacks.cpp @@ -23,7 +23,9 @@ * **/ #include "CommonDeviceCallbacks.h" +#include "AppTaskBase.h" +#include #include #include #include @@ -73,7 +75,7 @@ void chip::NXP::App::CommonDeviceCallbacks::DeviceEventCallback(const ChipDevice OnInterfaceIpAddressChanged(event); break; -#if CHIP_ENABLE_OPENTHREAD && CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED +#if CHIP_ENABLE_OPENTHREAD case DeviceEventType::kCommissioningComplete: CommonDeviceCallbacks::OnComissioningComplete(event); break; @@ -153,9 +155,25 @@ void chip::NXP::App::CommonDeviceCallbacks::OnSessionEstablished(chip::DeviceLay /* Empty */ } -#if CHIP_ENABLE_OPENTHREAD && CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED +#if CHIP_ENABLE_OPENTHREAD void chip::NXP::App::CommonDeviceCallbacks::OnComissioningComplete(const chip::DeviceLayer::ChipDeviceEvent * event) { +#ifndef _NO_GENERIC_THREAD_NETWORK_COMMISSIONING_DRIVER_ +#if CHIP_DEVICE_CONFIG_ENABLE_WPA + if (ConnectivityMgr().IsWiFiStationConnected()) + { + // Disable thr nwk commissioining cluster + app::Clusters::NetworkCommissioning::Attributes::InterfaceEnabled::Set(CHIP_DEVICE_CONFIG_THREAD_NETWORK_ENDPOINT_ID, 0); + } + else if (ConnectivityMgr().IsThreadProvisioned()) + { + // Set WIFI cluster interface attribute to disable. + app::Clusters::NetworkCommissioning::Attributes::InterfaceEnabled::Set(0, 0); + } +#endif // CHIP_DEVICE_CONFIG_ENABLE_WPA +#endif // _NO_GENERIC_THREAD_NETWORK_COMMISSIONING_DRIVER_ + +#if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED /* * If a transceiver supporting a multiprotocol scenario is used, a check of the provisioning state is required, * so that we can inform the transceiver to stop BLE to give the priority to another protocol. @@ -171,5 +189,6 @@ void chip::NXP::App::CommonDeviceCallbacks::OnComissioningComplete(const chip::D PlatformMgrImpl().StopBLEConnectivity(); ThreadStackMgrImpl().UnlockThreadStack(); } +#endif } #endif diff --git a/examples/platform/nxp/common/wifi_connect/include/WifiConnect.h b/examples/platform/nxp/common/wifi_connect/include/WifiConnect.h new file mode 100644 index 00000000000000..ea0b5cc9f4d8c1 --- /dev/null +++ b/examples/platform/nxp/common/wifi_connect/include/WifiConnect.h @@ -0,0 +1,42 @@ +/* + * + * 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. + */ + +/** + * @file WifiConnect.h + * + * Wi-Fi Connect Module allowing to join a pre-defined Wi-Fi network + * + **/ + +#pragma once + +#include + +namespace chip { +namespace NXP { +namespace App { + +/* + * Function allowing to join a Wi-Fi network based on Wi-Fi build credentials + * Must be called after completing Wi-Fi driver initialization + */ +CHIP_ERROR WifiConnectAtboot(chip::DeviceLayer::NetworkCommissioning::WiFiDriver * wifiDriver); + +} // namespace App +} // namespace NXP +} // namespace chip diff --git a/examples/platform/nxp/common/wifi_connect/source/WifiConnect.cpp b/examples/platform/nxp/common/wifi_connect/source/WifiConnect.cpp new file mode 100644 index 00000000000000..438bee5040795f --- /dev/null +++ b/examples/platform/nxp/common/wifi_connect/source/WifiConnect.cpp @@ -0,0 +1,53 @@ +/* + * + * 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. + */ + +#include "WifiConnect.h" +#include +#include +#include + +namespace chip { +namespace NXP { +namespace App { + +CHIP_ERROR WifiConnectAtboot(chip::DeviceLayer::NetworkCommissioning::WiFiDriver * wifiDriver) +{ + VerifyOrReturnError(wifiDriver != nullptr, CHIP_ERROR_NOT_IMPLEMENTED); + + /* In case WiFi connect at boot is enabled try to set SSID to the predefined value */ + ByteSpan ssidSpan = ByteSpan(Uint8::from_const_char(CONFIG_CHIP_APP_WIFI_SSID), strlen(CONFIG_CHIP_APP_WIFI_SSID)); + ByteSpan passwordSpan = ByteSpan(Uint8::from_const_char(CONFIG_CHIP_APP_WIFI_PASSWORD), strlen(CONFIG_CHIP_APP_WIFI_PASSWORD)); + VerifyOrReturnError(IsSpanUsable(ssidSpan) && IsSpanUsable(passwordSpan), CHIP_ERROR_INVALID_ARGUMENT); + + chip::DeviceLayer::NetworkCommissioning::NetworkIterator * networks = wifiDriver->GetNetworks(); + /* In case Wi-Fi driver has already Wi-Fi network information, skip the connect stage */ + if (networks == nullptr || networks->Count() == 0) + { + uint8_t networkIndex; + chip::MutableCharSpan debugText; + chip::DeviceLayer::NetworkCommissioning::Status status = + wifiDriver->AddOrUpdateNetwork(ssidSpan, passwordSpan, debugText, networkIndex); + VerifyOrReturnError(status == chip::DeviceLayer::NetworkCommissioning::Status::kSuccess, CHIP_ERROR_CONNECTION_ABORTED); + wifiDriver->ConnectNetwork(ssidSpan, nullptr); + } + return CHIP_NO_ERROR; +} + +} // namespace App +} // namespace NXP +} // namespace chip diff --git a/examples/thermostat/nxp/rt/rw61x/BUILD.gn b/examples/thermostat/nxp/rt/rw61x/BUILD.gn index 30af1be0e99a38..f377845cd49f98 100644 --- a/examples/thermostat/nxp/rt/rw61x/BUILD.gn +++ b/examples/thermostat/nxp/rt/rw61x/BUILD.gn @@ -35,15 +35,10 @@ assert(target_os == "freertos") assert(nxp_platform == "rt/rw61x") declare_args() { - # Allows to start the tcp download test app - tcp_download = false - - # Allows to start the wifi connect test app - wifi_connect = false - - # The 2 params below are used only if tcp_download or wifi_connect are true, otherwise they're unused. - wifi_ssid = "" - wifi_password = "" + # Allows to connect to a predefine Wi-Fi network at boot + wifi_auto_connect_at_boot = false + wifi_auto_connect_at_boot_ssid = "" + wifi_auto_connect_at_boot_password = "" # Setup discriminator as argument setup_discriminator = 3840 @@ -55,10 +50,6 @@ example_platform_dir = "${nxp_sdk_matter_support_root}/examples/platform/${nxp_platform}" common_example_dir = "${chip_root}/examples/platform/nxp/common" -if (tcp_download == true && wifi_connect == true) { - assert("Cannot enable tcp_download and wifi_connect at the same time!") -} - # Use NXP custom zap files for thermostatdevice-types app_common_folder = "thermostat/nxp/zap" @@ -107,10 +98,17 @@ rt_sdk("sdk") { # Indicate the default path to OpenThreadConfig.h include_dirs += [ "${example_platform_dir}/app/project_include/openthread" ] - # For matter with BR feature, increase FreeRTOS heap size + # For matter with BR feature, increase FreeRTOS heap size and enable TBR cluster if (chip_enable_wifi && chip_enable_openthread) { - defines += [ "configTOTAL_HEAP_SIZE=(size_t)(170 * 1024)" ] + defines += [ + "configTOTAL_HEAP_SIZE=(size_t)(170 * 1024)", + "CHIP_DEVICE_CONFIG_ENABLE_TBR=1", + ] } + + defines += [ + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setup_discriminator}", + ] } # Create the SDK driver instance. @@ -224,42 +222,21 @@ rt_executable("thermostat") { ] } - if (wifi_connect) { + if (wifi_auto_connect_at_boot) { + assert(wifi_auto_connect_at_boot_ssid != "" && + wifi_auto_connect_at_boot_password != "", + "WiFi SSID and password must be specified at build time!") + defines += [ - "WIFI_CONNECT_TASK=1", - "WIFI_CONNECT=1", + "CONFIG_CHIP_APP_WIFI_CONNECT_AT_BOOT=1", + "CONFIG_CHIP_APP_WIFI_SSID=\"${wifi_auto_connect_at_boot_ssid}\"", + "CONFIG_CHIP_APP_WIFI_PASSWORD=\"${wifi_auto_connect_at_boot_password}\"", ] - if (!chip_enable_matter_cli) { - assert(wifi_ssid != "" && wifi_password != "", - "WiFi SSID and password must be specified at build time!") - } - - if (wifi_ssid != "") { - defines += [ "WIFI_SSID=\"${wifi_ssid}\"" ] - } - - if (wifi_password != "") { - defines += [ "WIFI_PASSWORD=\"${wifi_password}\"" ] - } - include_dirs += [ "${common_example_dir}/wifi_connect/include" ] sources += [ "${common_example_dir}/wifi_connect/source/WifiConnect.cpp" ] } - if (tcp_download) { - defines += [ "CONFIG_CHIP_TCP_DOWNLOAD=1" ] - defines += [ - "WIFI_CONNECT=1", - "WIFI_SSID=\"${wifi_ssid}\"", - "WIFI_PASSWORD=\"${wifi_password}\"", - ] - - include_dirs += [ "${common_example_dir}/tcp_download_test/include" ] - sources += - [ "${common_example_dir}/tcp_download_test/source/TcpDownload.cpp" ] - } - # In case a dedicated assert function needs to be supported the flag sdk_fsl_assert_support should be set to false # The would add to the build a dedicated application assert implementation. if (!sdk_fsl_assert_support) { @@ -298,10 +275,6 @@ rt_executable("thermostat") { # Consequently, some sections will need to be shifted ldflags += [ "-Wl,--defsym=__m_mcuboot_size__=0x20000" ] } - - defines += [ - "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setup_discriminator}", - ] } output_dir = root_out_dir diff --git a/examples/thermostat/nxp/zap/BUILD.gn b/examples/thermostat/nxp/zap/BUILD.gn index c3a3df7bd6729e..f3c652493dd3fb 100644 --- a/examples/thermostat/nxp/zap/BUILD.gn +++ b/examples/thermostat/nxp/zap/BUILD.gn @@ -20,7 +20,10 @@ import("${chip_root}/src/app/chip_data_model.gni") import("${chip_root}/src/platform/device.gni") chip_data_model("zap") { - if (chip_enable_wifi) { + if (chip_enable_wifi && chip_enable_openthread) { + # zap config for matter-over-wifi with BR + zap_file = "thermostat_matter_br.zap" + } else if (chip_enable_wifi) { # zap config for matter-over-wifi zap_file = "thermostat_matter_wifi.zap" } else { diff --git a/examples/thermostat/nxp/zap/thermostat_matter_br.matter b/examples/thermostat/nxp/zap/thermostat_matter_br.matter new file mode 100644 index 00000000000000..bb72c0caceaf27 --- /dev/null +++ b/examples/thermostat/nxp/zap/thermostat_matter_br.matter @@ -0,0 +1,2766 @@ +// This IDL was generated automatically by ZAP. +// It is for view/code review purposes only. + +enum AreaTypeTag : enum8 { + kAisle = 0; + kAttic = 1; + kBackDoor = 2; + kBackYard = 3; + kBalcony = 4; + kBallroom = 5; + kBathroom = 6; + kBedroom = 7; + kBorder = 8; + kBoxroom = 9; + kBreakfastRoom = 10; + kCarport = 11; + kCellar = 12; + kCloakroom = 13; + kCloset = 14; + kConservatory = 15; + kCorridor = 16; + kCraftRoom = 17; + kCupboard = 18; + kDeck = 19; + kDen = 20; + kDining = 21; + kDrawingRoom = 22; + kDressingRoom = 23; + kDriveway = 24; + kElevator = 25; + kEnsuite = 26; + kEntrance = 27; + kEntryway = 28; + kFamilyRoom = 29; + kFoyer = 30; + kFrontDoor = 31; + kFrontYard = 32; + kGameRoom = 33; + kGarage = 34; + kGarageDoor = 35; + kGarden = 36; + kGardenDoor = 37; + kGuestBathroom = 38; + kGuestBedroom = 39; + kGuestRestroom = 40; + kGuestRoom = 41; + kGym = 42; + kHallway = 43; + kHearthRoom = 44; + kKidsRoom = 45; + kKidsBedroom = 46; + kKitchen = 47; + kLarder = 48; + kLaundryRoom = 49; + kLawn = 50; + kLibrary = 51; + kLivingRoom = 52; + kLounge = 53; + kMediaTVRoom = 54; + kMudRoom = 55; + kMusicRoom = 56; + kNursery = 57; + kOffice = 58; + kOutdoorKitchen = 59; + kOutside = 60; + kPantry = 61; + kParkingLot = 62; + kParlor = 63; + kPatio = 64; + kPlayRoom = 65; + kPoolRoom = 66; + kPorch = 67; + kPrimaryBathroom = 68; + kPrimaryBedroom = 69; + kRamp = 70; + kReceptionRoom = 71; + kRecreationRoom = 72; + kRestroom = 73; + kRoof = 74; + kSauna = 75; + kScullery = 76; + kSewingRoom = 77; + kShed = 78; + kSideDoor = 79; + kSideYard = 80; + kSittingRoom = 81; + kSnug = 82; + kSpa = 83; + kStaircase = 84; + kSteamRoom = 85; + kStorageRoom = 86; + kStudio = 87; + kStudy = 88; + kSunRoom = 89; + kSwimmingPool = 90; + kTerrace = 91; + kUtilityRoom = 92; + kWard = 93; + kWorkshop = 94; +} + +enum AtomicRequestTypeEnum : enum8 { + kBeginWrite = 0; + kCommitWrite = 1; + kRollbackWrite = 2; +} + +enum FloorSurfaceTag : enum8 { + kCarpet = 0; + kCeramic = 1; + kConcrete = 2; + kCork = 3; + kDeepCarpet = 4; + kDirt = 5; + kEngineeredWood = 6; + kGlass = 7; + kGrass = 8; + kHardwood = 9; + kLaminate = 10; + kLinoleum = 11; + kMat = 12; + kMetal = 13; + kPlastic = 14; + kPolishedConcrete = 15; + kRubber = 16; + kRug = 17; + kSand = 18; + kStone = 19; + kTatami = 20; + kTerrazzo = 21; + kTile = 22; + kVinyl = 23; +} + +enum LandmarkTag : enum8 { + kAirConditioner = 0; + kAirPurifier = 1; + kBackDoor = 2; + kBarStool = 3; + kBathMat = 4; + kBathtub = 5; + kBed = 6; + kBookshelf = 7; + kChair = 8; + kChristmasTree = 9; + kCoatRack = 10; + kCoffeeTable = 11; + kCookingRange = 12; + kCouch = 13; + kCountertop = 14; + kCradle = 15; + kCrib = 16; + kDesk = 17; + kDiningTable = 18; + kDishwasher = 19; + kDoor = 20; + kDresser = 21; + kLaundryDryer = 22; + kFan = 23; + kFireplace = 24; + kFreezer = 25; + kFrontDoor = 26; + kHighChair = 27; + kKitchenIsland = 28; + kLamp = 29; + kLitterBox = 30; + kMirror = 31; + kNightstand = 32; + kOven = 33; + kPetBed = 34; + kPetBowl = 35; + kPetCrate = 36; + kRefrigerator = 37; + kScratchingPost = 38; + kShoeRack = 39; + kShower = 40; + kSideDoor = 41; + kSink = 42; + kSofa = 43; + kStove = 44; + kTable = 45; + kToilet = 46; + kTrashCan = 47; + kLaundryWasher = 48; + kWindow = 49; + kWineCooler = 50; +} + +enum PositionTag : enum8 { + kLeft = 0; + kRight = 1; + kTop = 2; + kBottom = 3; + kMiddle = 4; + kRow = 5; + kColumn = 6; +} + +enum RelativePositionTag : enum8 { + kUnder = 0; + kNextTo = 1; + kAround = 2; + kOn = 3; + kAbove = 4; + kFrontOf = 5; + kBehind = 6; +} + +enum TestGlobalEnum : enum8 { + kSomeValue = 0; + kSomeOtherValue = 1; + kFinalValue = 2; +} + +bitmap TestGlobalBitmap : bitmap32 { + kFirstBit = 0x1; + kSecondBit = 0x2; +} + +struct TestGlobalStruct { + char_string<128> name = 0; + nullable TestGlobalBitmap myBitmap = 1; + optional nullable TestGlobalEnum myEnum = 2; +} + +struct LocationDescriptorStruct { + char_string<128> locationName = 0; + nullable int16s floorNumber = 1; + nullable AreaTypeTag areaType = 2; +} + +struct AtomicAttributeStatusStruct { + attrib_id attributeID = 0; + status statusCode = 1; +} + +/** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ +cluster Identify = 3 { + revision 4; + + enum EffectIdentifierEnum : enum8 { + kBlink = 0; + kBreathe = 1; + kOkay = 2; + kChannelChange = 11; + kFinishEffect = 254; + kStopEffect = 255; + } + + enum EffectVariantEnum : enum8 { + kDefault = 0; + } + + enum IdentifyTypeEnum : enum8 { + kNone = 0; + kLightOutput = 1; + kVisibleIndicator = 2; + kAudibleBeep = 3; + kDisplay = 4; + kActuator = 5; + } + + attribute int16u identifyTime = 0; + readonly attribute IdentifyTypeEnum identifyType = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct IdentifyRequest { + int16u identifyTime = 0; + } + + request struct TriggerEffectRequest { + EffectIdentifierEnum effectIdentifier = 0; + EffectVariantEnum effectVariant = 1; + } + + /** Command description for Identify */ + command access(invoke: manage) Identify(IdentifyRequest): DefaultSuccess = 0; + /** Command description for TriggerEffect */ + command access(invoke: manage) TriggerEffect(TriggerEffectRequest): DefaultSuccess = 64; +} + +/** Attributes and commands for putting a device into Identification mode (e.g. flashing a light). */ +cluster Identify = 3 { + revision 4; + + enum EffectIdentifierEnum : enum8 { + kBlink = 0; + kBreathe = 1; + kOkay = 2; + kChannelChange = 11; + kFinishEffect = 254; + kStopEffect = 255; + } + + enum EffectVariantEnum : enum8 { + kDefault = 0; + } + + enum IdentifyTypeEnum : enum8 { + kNone = 0; + kLightOutput = 1; + kVisibleIndicator = 2; + kAudibleBeep = 3; + kDisplay = 4; + kActuator = 5; + } + + attribute int16u identifyTime = 0; + readonly attribute IdentifyTypeEnum identifyType = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct IdentifyRequest { + int16u identifyTime = 0; + } + + request struct TriggerEffectRequest { + EffectIdentifierEnum effectIdentifier = 0; + EffectVariantEnum effectVariant = 1; + } + + /** Command description for Identify */ + command access(invoke: manage) Identify(IdentifyRequest): DefaultSuccess = 0; + /** Command description for TriggerEffect */ + command access(invoke: manage) TriggerEffect(TriggerEffectRequest): DefaultSuccess = 64; +} + +/** Attributes and commands for group configuration and manipulation. */ +cluster Groups = 4 { + revision 4; + + bitmap Feature : bitmap32 { + kGroupNames = 0x1; + } + + bitmap NameSupportBitmap : bitmap8 { + kGroupNames = 0x80; + } + + readonly attribute NameSupportBitmap nameSupport = 0; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AddGroupRequest { + group_id groupID = 0; + char_string<16> groupName = 1; + } + + response struct AddGroupResponse = 0 { + enum8 status = 0; + group_id groupID = 1; + } + + request struct ViewGroupRequest { + group_id groupID = 0; + } + + response struct ViewGroupResponse = 1 { + enum8 status = 0; + group_id groupID = 1; + char_string<16> groupName = 2; + } + + request struct GetGroupMembershipRequest { + group_id groupList[] = 0; + } + + response struct GetGroupMembershipResponse = 2 { + nullable int8u capacity = 0; + group_id groupList[] = 1; + } + + request struct RemoveGroupRequest { + group_id groupID = 0; + } + + response struct RemoveGroupResponse = 3 { + enum8 status = 0; + group_id groupID = 1; + } + + request struct AddGroupIfIdentifyingRequest { + group_id groupID = 0; + char_string<16> groupName = 1; + } + + /** Command description for AddGroup */ + fabric command access(invoke: manage) AddGroup(AddGroupRequest): AddGroupResponse = 0; + /** Command description for ViewGroup */ + fabric command ViewGroup(ViewGroupRequest): ViewGroupResponse = 1; + /** Command description for GetGroupMembership */ + fabric command GetGroupMembership(GetGroupMembershipRequest): GetGroupMembershipResponse = 2; + /** Command description for RemoveGroup */ + fabric command access(invoke: manage) RemoveGroup(RemoveGroupRequest): RemoveGroupResponse = 3; + /** Command description for RemoveAllGroups */ + fabric command access(invoke: manage) RemoveAllGroups(): DefaultSuccess = 4; + /** Command description for AddGroupIfIdentifying */ + fabric command access(invoke: manage) AddGroupIfIdentifying(AddGroupIfIdentifyingRequest): DefaultSuccess = 5; +} + +/** The Descriptor Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for describing a node, its endpoints and clusters. */ +cluster Descriptor = 29 { + revision 2; + + bitmap Feature : bitmap32 { + kTagList = 0x1; + } + + struct DeviceTypeStruct { + devtype_id deviceType = 0; + int16u revision = 1; + } + + struct SemanticTagStruct { + nullable vendor_id mfgCode = 0; + enum8 namespaceID = 1; + enum8 tag = 2; + optional nullable char_string label = 3; + } + + readonly attribute DeviceTypeStruct deviceTypeList[] = 0; + readonly attribute cluster_id serverList[] = 1; + readonly attribute cluster_id clientList[] = 2; + readonly attribute endpoint_no partsList[] = 3; + readonly attribute optional SemanticTagStruct tagList[] = 4; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** The Binding Cluster is meant to replace the support from the Zigbee Device Object (ZDO) for supporting the binding table. */ +cluster Binding = 30 { + revision 1; // NOTE: Default/not specifically set + + fabric_scoped struct TargetStruct { + optional node_id node = 1; + optional group_id group = 2; + optional endpoint_no endpoint = 3; + optional cluster_id cluster = 4; + fabric_idx fabricIndex = 254; + } + + attribute access(write: manage) TargetStruct binding[] = 0; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** The Access Control Cluster exposes a data model view of a + Node's Access Control List (ACL), which codifies the rules used to manage + and enforce Access Control for the Node's endpoints and their associated + cluster instances. */ +cluster AccessControl = 31 { + revision 2; + + enum AccessControlEntryAuthModeEnum : enum8 { + kPASE = 1; + kCASE = 2; + kGroup = 3; + } + + enum AccessControlEntryPrivilegeEnum : enum8 { + kView = 1; + kProxyView = 2; + kOperate = 3; + kManage = 4; + kAdminister = 5; + } + + enum AccessRestrictionTypeEnum : enum8 { + kAttributeAccessForbidden = 0; + kAttributeWriteForbidden = 1; + kCommandForbidden = 2; + kEventForbidden = 3; + } + + enum ChangeTypeEnum : enum8 { + kChanged = 0; + kAdded = 1; + kRemoved = 2; + } + + bitmap Feature : bitmap32 { + kExtension = 0x1; + kManagedDevice = 0x2; + } + + struct AccessRestrictionStruct { + AccessRestrictionTypeEnum type = 0; + nullable int32u id = 1; + } + + struct CommissioningAccessRestrictionEntryStruct { + endpoint_no endpoint = 0; + cluster_id cluster = 1; + AccessRestrictionStruct restrictions[] = 2; + } + + fabric_scoped struct AccessRestrictionEntryStruct { + fabric_sensitive endpoint_no endpoint = 0; + fabric_sensitive cluster_id cluster = 1; + fabric_sensitive AccessRestrictionStruct restrictions[] = 2; + fabric_idx fabricIndex = 254; + } + + struct AccessControlTargetStruct { + nullable cluster_id cluster = 0; + nullable endpoint_no endpoint = 1; + nullable devtype_id deviceType = 2; + } + + fabric_scoped struct AccessControlEntryStruct { + fabric_sensitive AccessControlEntryPrivilegeEnum privilege = 1; + fabric_sensitive AccessControlEntryAuthModeEnum authMode = 2; + nullable fabric_sensitive int64u subjects[] = 3; + nullable fabric_sensitive AccessControlTargetStruct targets[] = 4; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct AccessControlExtensionStruct { + fabric_sensitive octet_string<128> data = 1; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) AccessControlEntryChanged = 0 { + nullable node_id adminNodeID = 1; + nullable int16u adminPasscodeID = 2; + ChangeTypeEnum changeType = 3; + nullable AccessControlEntryStruct latestValue = 4; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) AccessControlExtensionChanged = 1 { + nullable node_id adminNodeID = 1; + nullable int16u adminPasscodeID = 2; + ChangeTypeEnum changeType = 3; + nullable AccessControlExtensionStruct latestValue = 4; + fabric_idx fabricIndex = 254; + } + + fabric_sensitive info event access(read: administer) FabricRestrictionReviewUpdate = 2 { + int64u token = 0; + optional long_char_string instruction = 1; + optional long_char_string ARLRequestFlowUrl = 2; + fabric_idx fabricIndex = 254; + } + + attribute access(read: administer, write: administer) AccessControlEntryStruct acl[] = 0; + attribute access(read: administer, write: administer) optional AccessControlExtensionStruct extension[] = 1; + readonly attribute int16u subjectsPerAccessControlEntry = 2; + readonly attribute int16u targetsPerAccessControlEntry = 3; + readonly attribute int16u accessControlEntriesPerFabric = 4; + readonly attribute optional CommissioningAccessRestrictionEntryStruct commissioningARL[] = 5; + readonly attribute optional AccessRestrictionEntryStruct arl[] = 6; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ReviewFabricRestrictionsRequest { + CommissioningAccessRestrictionEntryStruct arl[] = 0; + } + + response struct ReviewFabricRestrictionsResponse = 1 { + int64u token = 0; + } + + /** This command signals to the service associated with the device vendor that the fabric administrator would like a review of the current restrictions on the accessing fabric. */ + fabric command access(invoke: administer) ReviewFabricRestrictions(ReviewFabricRestrictionsRequest): ReviewFabricRestrictionsResponse = 0; +} + +/** This cluster provides attributes and events for determining basic information about Nodes, which supports both + Commissioning and operational determination of Node characteristics, such as Vendor ID, Product ID and serial number, + which apply to the whole Node. Also allows setting user device information such as location. */ +cluster BasicInformation = 40 { + revision 3; + + enum ColorEnum : enum8 { + kBlack = 0; + kNavy = 1; + kGreen = 2; + kTeal = 3; + kMaroon = 4; + kPurple = 5; + kOlive = 6; + kGray = 7; + kBlue = 8; + kLime = 9; + kAqua = 10; + kRed = 11; + kFuchsia = 12; + kYellow = 13; + kWhite = 14; + kNickel = 15; + kChrome = 16; + kBrass = 17; + kCopper = 18; + kSilver = 19; + kGold = 20; + } + + enum ProductFinishEnum : enum8 { + kOther = 0; + kMatte = 1; + kSatin = 2; + kPolished = 3; + kRugged = 4; + kFabric = 5; + } + + struct CapabilityMinimaStruct { + int16u caseSessionsPerFabric = 0; + int16u subscriptionsPerFabric = 1; + } + + struct ProductAppearanceStruct { + ProductFinishEnum finish = 0; + nullable ColorEnum primaryColor = 1; + } + + critical event StartUp = 0 { + int32u softwareVersion = 0; + } + + critical event ShutDown = 1 { + } + + info event Leave = 2 { + fabric_idx fabricIndex = 0; + } + + info event ReachableChanged = 3 { + boolean reachableNewValue = 0; + } + + readonly attribute int16u dataModelRevision = 0; + readonly attribute char_string<32> vendorName = 1; + readonly attribute vendor_id vendorID = 2; + readonly attribute char_string<32> productName = 3; + readonly attribute int16u productID = 4; + attribute access(write: manage) char_string<32> nodeLabel = 5; + attribute access(write: administer) char_string<2> location = 6; + readonly attribute int16u hardwareVersion = 7; + readonly attribute char_string<64> hardwareVersionString = 8; + readonly attribute int32u softwareVersion = 9; + readonly attribute char_string<64> softwareVersionString = 10; + readonly attribute optional char_string<16> manufacturingDate = 11; + readonly attribute optional char_string<32> partNumber = 12; + readonly attribute optional long_char_string<256> productURL = 13; + readonly attribute optional char_string<64> productLabel = 14; + readonly attribute optional char_string<32> serialNumber = 15; + attribute access(write: manage) optional boolean localConfigDisabled = 16; + readonly attribute optional boolean reachable = 17; + readonly attribute char_string<32> uniqueID = 18; + readonly attribute CapabilityMinimaStruct capabilityMinima = 19; + readonly attribute optional ProductAppearanceStruct productAppearance = 20; + readonly attribute int32u specificationVersion = 21; + readonly attribute int16u maxPathsPerInvoke = 22; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + command MfgSpecificPing(): DefaultSuccess = 0; +} + +/** Provides an interface for providing OTA software updates */ +cluster OtaSoftwareUpdateProvider = 41 { + revision 1; // NOTE: Default/not specifically set + + enum ApplyUpdateActionEnum : enum8 { + kProceed = 0; + kAwaitNextAction = 1; + kDiscontinue = 2; + } + + enum DownloadProtocolEnum : enum8 { + kBDXSynchronous = 0; + kBDXAsynchronous = 1; + kHTTPS = 2; + kVendorSpecific = 3; + } + + enum StatusEnum : enum8 { + kUpdateAvailable = 0; + kBusy = 1; + kNotAvailable = 2; + kDownloadProtocolNotSupported = 3; + } + + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct QueryImageRequest { + vendor_id vendorID = 0; + int16u productID = 1; + int32u softwareVersion = 2; + DownloadProtocolEnum protocolsSupported[] = 3; + optional int16u hardwareVersion = 4; + optional char_string<2> location = 5; + optional boolean requestorCanConsent = 6; + optional octet_string<512> metadataForProvider = 7; + } + + response struct QueryImageResponse = 1 { + StatusEnum status = 0; + optional int32u delayedActionTime = 1; + optional char_string<256> imageURI = 2; + optional int32u softwareVersion = 3; + optional char_string<64> softwareVersionString = 4; + optional octet_string<32> updateToken = 5; + optional boolean userConsentNeeded = 6; + optional octet_string<512> metadataForRequestor = 7; + } + + request struct ApplyUpdateRequestRequest { + octet_string<32> updateToken = 0; + int32u newVersion = 1; + } + + response struct ApplyUpdateResponse = 3 { + ApplyUpdateActionEnum action = 0; + int32u delayedActionTime = 1; + } + + request struct NotifyUpdateAppliedRequest { + octet_string<32> updateToken = 0; + int32u softwareVersion = 1; + } + + /** Determine availability of a new Software Image */ + command QueryImage(QueryImageRequest): QueryImageResponse = 0; + /** Determine next action to take for a downloaded Software Image */ + command ApplyUpdateRequest(ApplyUpdateRequestRequest): ApplyUpdateResponse = 2; + /** Notify OTA Provider that an update was applied */ + command NotifyUpdateApplied(NotifyUpdateAppliedRequest): DefaultSuccess = 4; +} + +/** Provides an interface for downloading and applying OTA software updates */ +cluster OtaSoftwareUpdateRequestor = 42 { + revision 1; // NOTE: Default/not specifically set + + enum AnnouncementReasonEnum : enum8 { + kSimpleAnnouncement = 0; + kUpdateAvailable = 1; + kUrgentUpdateAvailable = 2; + } + + enum ChangeReasonEnum : enum8 { + kUnknown = 0; + kSuccess = 1; + kFailure = 2; + kTimeOut = 3; + kDelayByProvider = 4; + } + + enum UpdateStateEnum : enum8 { + kUnknown = 0; + kIdle = 1; + kQuerying = 2; + kDelayedOnQuery = 3; + kDownloading = 4; + kApplying = 5; + kDelayedOnApply = 6; + kRollingBack = 7; + kDelayedOnUserConsent = 8; + } + + fabric_scoped struct ProviderLocation { + node_id providerNodeID = 1; + endpoint_no endpoint = 2; + fabric_idx fabricIndex = 254; + } + + info event StateTransition = 0 { + UpdateStateEnum previousState = 0; + UpdateStateEnum newState = 1; + ChangeReasonEnum reason = 2; + nullable int32u targetSoftwareVersion = 3; + } + + critical event VersionApplied = 1 { + int32u softwareVersion = 0; + int16u productID = 1; + } + + info event DownloadError = 2 { + int32u softwareVersion = 0; + int64u bytesDownloaded = 1; + nullable int8u progressPercent = 2; + nullable int64s platformCode = 3; + } + + attribute access(write: administer) ProviderLocation defaultOTAProviders[] = 0; + readonly attribute boolean updatePossible = 1; + readonly attribute UpdateStateEnum updateState = 2; + readonly attribute nullable int8u updateStateProgress = 3; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AnnounceOTAProviderRequest { + node_id providerNodeID = 0; + vendor_id vendorID = 1; + AnnouncementReasonEnum announcementReason = 2; + optional octet_string<512> metadataForNode = 3; + endpoint_no endpoint = 4; + } + + /** Announce the presence of an OTA Provider */ + command AnnounceOTAProvider(AnnounceOTAProviderRequest): DefaultSuccess = 0; +} + +/** Nodes should be expected to be deployed to any and all regions of the world. These global regions + may have differing common languages, units of measurements, and numerical formatting + standards. As such, Nodes that visually or audibly convey information need a mechanism by which + they can be configured to use a user’s preferred language, units, etc */ +cluster LocalizationConfiguration = 43 { + revision 1; // NOTE: Default/not specifically set + + attribute access(write: manage) char_string<35> activeLocale = 0; + readonly attribute char_string supportedLocales[] = 1; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** Nodes should be expected to be deployed to any and all regions of the world. These global regions + may have differing preferences for how dates and times are conveyed. As such, Nodes that visually + or audibly convey time information need a mechanism by which they can be configured to use a + user’s preferred format. */ +cluster TimeFormatLocalization = 44 { + revision 1; // NOTE: Default/not specifically set + + enum CalendarTypeEnum : enum8 { + kBuddhist = 0; + kChinese = 1; + kCoptic = 2; + kEthiopian = 3; + kGregorian = 4; + kHebrew = 5; + kIndian = 6; + kIslamic = 7; + kJapanese = 8; + kKorean = 9; + kPersian = 10; + kTaiwanese = 11; + kUseActiveLocale = 255; + } + + enum HourFormatEnum : enum8 { + k12hr = 0; + k24hr = 1; + kUseActiveLocale = 255; + } + + bitmap Feature : bitmap32 { + kCalendarFormat = 0x1; + } + + attribute access(write: manage) HourFormatEnum hourFormat = 0; + attribute access(write: manage) optional CalendarTypeEnum activeCalendarType = 1; + readonly attribute optional CalendarTypeEnum supportedCalendarTypes[] = 2; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** Nodes should be expected to be deployed to any and all regions of the world. These global regions + may have differing preferences for the units in which values are conveyed in communication to a + user. As such, Nodes that visually or audibly convey measurable values to the user need a + mechanism by which they can be configured to use a user’s preferred unit. */ +cluster UnitLocalization = 45 { + revision 1; + + enum TempUnitEnum : enum8 { + kFahrenheit = 0; + kCelsius = 1; + kKelvin = 2; + } + + bitmap Feature : bitmap32 { + kTemperatureUnit = 0x1; + } + + attribute access(write: manage) optional TempUnitEnum temperatureUnit = 0; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** This cluster is used to manage global aspects of the Commissioning flow. */ +cluster GeneralCommissioning = 48 { + revision 1; // NOTE: Default/not specifically set + + enum CommissioningErrorEnum : enum8 { + kOK = 0; + kValueOutsideRange = 1; + kInvalidAuthentication = 2; + kNoFailSafe = 3; + kBusyWithOtherAdmin = 4; + kRequiredTCNotAccepted = 5; + kTCAcknowledgementsNotReceived = 6; + kTCMinVersionNotMet = 7; + } + + enum RegulatoryLocationTypeEnum : enum8 { + kIndoor = 0; + kOutdoor = 1; + kIndoorOutdoor = 2; + } + + bitmap Feature : bitmap32 { + kTermsAndConditions = 0x1; + } + + struct BasicCommissioningInfo { + int16u failSafeExpiryLengthSeconds = 0; + int16u maxCumulativeFailsafeSeconds = 1; + } + + attribute access(write: administer) int64u breadcrumb = 0; + readonly attribute BasicCommissioningInfo basicCommissioningInfo = 1; + readonly attribute RegulatoryLocationTypeEnum regulatoryConfig = 2; + readonly attribute RegulatoryLocationTypeEnum locationCapability = 3; + readonly attribute boolean supportsConcurrentConnection = 4; + provisional readonly attribute access(read: administer) optional int16u TCAcceptedVersion = 5; + provisional readonly attribute access(read: administer) optional int16u TCMinRequiredVersion = 6; + provisional readonly attribute access(read: administer) optional bitmap16 TCAcknowledgements = 7; + provisional readonly attribute access(read: administer) optional boolean TCAcknowledgementsRequired = 8; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ArmFailSafeRequest { + int16u expiryLengthSeconds = 0; + int64u breadcrumb = 1; + } + + response struct ArmFailSafeResponse = 1 { + CommissioningErrorEnum errorCode = 0; + char_string<128> debugText = 1; + } + + request struct SetRegulatoryConfigRequest { + RegulatoryLocationTypeEnum newRegulatoryConfig = 0; + char_string<2> countryCode = 1; + int64u breadcrumb = 2; + } + + response struct SetRegulatoryConfigResponse = 3 { + CommissioningErrorEnum errorCode = 0; + char_string debugText = 1; + } + + response struct CommissioningCompleteResponse = 5 { + CommissioningErrorEnum errorCode = 0; + char_string debugText = 1; + } + + request struct SetTCAcknowledgementsRequest { + int16u TCVersion = 0; + bitmap16 TCUserResponse = 1; + } + + response struct SetTCAcknowledgementsResponse = 7 { + CommissioningErrorEnum errorCode = 0; + } + + /** Arm the persistent fail-safe timer with an expiry time of now + ExpiryLengthSeconds using device clock */ + command access(invoke: administer) ArmFailSafe(ArmFailSafeRequest): ArmFailSafeResponse = 0; + /** Set the regulatory configuration to be used during commissioning */ + command access(invoke: administer) SetRegulatoryConfig(SetRegulatoryConfigRequest): SetRegulatoryConfigResponse = 2; + /** Signals the Server that the Client has successfully completed all steps of Commissioning/Recofiguration needed during fail-safe period. */ + fabric command access(invoke: administer) CommissioningComplete(): CommissioningCompleteResponse = 4; + /** This command sets the user acknowledgements received in the Enhanced Setup Flow Terms and Conditions into the node. */ + command access(invoke: administer) SetTCAcknowledgements(SetTCAcknowledgementsRequest): SetTCAcknowledgementsResponse = 6; +} + +/** Functionality to configure, enable, disable network credentials and access on a Matter device. */ +cluster NetworkCommissioning = 49 { + revision 1; // NOTE: Default/not specifically set + + enum NetworkCommissioningStatusEnum : enum8 { + kSuccess = 0; + kOutOfRange = 1; + kBoundsExceeded = 2; + kNetworkIDNotFound = 3; + kDuplicateNetworkID = 4; + kNetworkNotFound = 5; + kRegulatoryError = 6; + kAuthFailure = 7; + kUnsupportedSecurity = 8; + kOtherConnectionFailure = 9; + kIPV6Failed = 10; + kIPBindFailed = 11; + kUnknownError = 12; + } + + enum WiFiBandEnum : enum8 { + k2G4 = 0; + k3G65 = 1; + k5G = 2; + k6G = 3; + k60G = 4; + k1G = 5; + } + + bitmap Feature : bitmap32 { + kWiFiNetworkInterface = 0x1; + kThreadNetworkInterface = 0x2; + kEthernetNetworkInterface = 0x4; + kPerDeviceCredentials = 0x8; + } + + bitmap ThreadCapabilitiesBitmap : bitmap16 { + kIsBorderRouterCapable = 0x1; + kIsRouterCapable = 0x2; + kIsSleepyEndDeviceCapable = 0x4; + kIsFullThreadDevice = 0x8; + kIsSynchronizedSleepyEndDeviceCapable = 0x10; + } + + bitmap WiFiSecurityBitmap : bitmap8 { + kUnencrypted = 0x1; + kWEP = 0x2; + kWPAPersonal = 0x4; + kWPA2Personal = 0x8; + kWPA3Personal = 0x10; + kWPA3MatterPDC = 0x20; + } + + struct NetworkInfoStruct { + octet_string<32> networkID = 0; + boolean connected = 1; + optional nullable octet_string<20> networkIdentifier = 2; + optional nullable octet_string<20> clientIdentifier = 3; + } + + struct ThreadInterfaceScanResultStruct { + int16u panId = 0; + int64u extendedPanId = 1; + char_string<16> networkName = 2; + int16u channel = 3; + int8u version = 4; + octet_string<8> extendedAddress = 5; + int8s rssi = 6; + int8u lqi = 7; + } + + struct WiFiInterfaceScanResultStruct { + WiFiSecurityBitmap security = 0; + octet_string<32> ssid = 1; + octet_string<6> bssid = 2; + int16u channel = 3; + WiFiBandEnum wiFiBand = 4; + int8s rssi = 5; + } + + readonly attribute access(read: administer) int8u maxNetworks = 0; + readonly attribute access(read: administer) NetworkInfoStruct networks[] = 1; + readonly attribute optional int8u scanMaxTimeSeconds = 2; + readonly attribute optional int8u connectMaxTimeSeconds = 3; + attribute access(write: administer) boolean interfaceEnabled = 4; + readonly attribute access(read: administer) nullable NetworkCommissioningStatusEnum lastNetworkingStatus = 5; + readonly attribute access(read: administer) nullable octet_string<32> lastNetworkID = 6; + readonly attribute access(read: administer) nullable int32s lastConnectErrorValue = 7; + provisional readonly attribute optional WiFiBandEnum supportedWiFiBands[] = 8; + provisional readonly attribute optional ThreadCapabilitiesBitmap supportedThreadFeatures = 9; + provisional readonly attribute optional int16u threadVersion = 10; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct ScanNetworksRequest { + optional nullable octet_string<32> ssid = 0; + optional int64u breadcrumb = 1; + } + + response struct ScanNetworksResponse = 1 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string debugText = 1; + optional WiFiInterfaceScanResultStruct wiFiScanResults[] = 2; + optional ThreadInterfaceScanResultStruct threadScanResults[] = 3; + } + + request struct AddOrUpdateWiFiNetworkRequest { + octet_string<32> ssid = 0; + octet_string<64> credentials = 1; + optional int64u breadcrumb = 2; + optional octet_string<140> networkIdentity = 3; + optional octet_string<20> clientIdentifier = 4; + optional octet_string<32> possessionNonce = 5; + } + + request struct AddOrUpdateThreadNetworkRequest { + octet_string<254> operationalDataset = 0; + optional int64u breadcrumb = 1; + } + + request struct RemoveNetworkRequest { + octet_string<32> networkID = 0; + optional int64u breadcrumb = 1; + } + + response struct NetworkConfigResponse = 5 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string<512> debugText = 1; + optional int8u networkIndex = 2; + optional octet_string<140> clientIdentity = 3; + optional octet_string<64> possessionSignature = 4; + } + + request struct ConnectNetworkRequest { + octet_string<32> networkID = 0; + optional int64u breadcrumb = 1; + } + + response struct ConnectNetworkResponse = 7 { + NetworkCommissioningStatusEnum networkingStatus = 0; + optional char_string debugText = 1; + nullable int32s errorValue = 2; + } + + request struct ReorderNetworkRequest { + octet_string<32> networkID = 0; + int8u networkIndex = 1; + optional int64u breadcrumb = 2; + } + + request struct QueryIdentityRequest { + octet_string<20> keyIdentifier = 0; + optional octet_string<32> possessionNonce = 1; + } + + response struct QueryIdentityResponse = 10 { + octet_string<140> identity = 0; + optional octet_string<64> possessionSignature = 1; + } + + /** Detemine the set of networks the device sees as available. */ + command access(invoke: administer) ScanNetworks(ScanNetworksRequest): ScanNetworksResponse = 0; + /** Add or update the credentials for a given Wi-Fi network. */ + command access(invoke: administer) AddOrUpdateWiFiNetwork(AddOrUpdateWiFiNetworkRequest): NetworkConfigResponse = 2; + /** Add or update the credentials for a given Thread network. */ + command access(invoke: administer) AddOrUpdateThreadNetwork(AddOrUpdateThreadNetworkRequest): NetworkConfigResponse = 3; + /** Remove the definition of a given network (including its credentials). */ + command access(invoke: administer) RemoveNetwork(RemoveNetworkRequest): NetworkConfigResponse = 4; + /** Connect to the specified network, using previously-defined credentials. */ + command access(invoke: administer) ConnectNetwork(ConnectNetworkRequest): ConnectNetworkResponse = 6; + /** Modify the order in which networks will be presented in the Networks attribute. */ + command access(invoke: administer) ReorderNetwork(ReorderNetworkRequest): NetworkConfigResponse = 8; + /** Retrieve details about and optionally proof of possession of a network client identity. */ + command access(invoke: administer) QueryIdentity(QueryIdentityRequest): QueryIdentityResponse = 9; +} + +/** The cluster provides commands for retrieving unstructured diagnostic logs from a Node that may be used to aid in diagnostics. */ +cluster DiagnosticLogs = 50 { + revision 1; // NOTE: Default/not specifically set + + enum IntentEnum : enum8 { + kEndUserSupport = 0; + kNetworkDiag = 1; + kCrashLogs = 2; + } + + enum StatusEnum : enum8 { + kSuccess = 0; + kExhausted = 1; + kNoLogs = 2; + kBusy = 3; + kDenied = 4; + } + + enum TransferProtocolEnum : enum8 { + kResponsePayload = 0; + kBDX = 1; + } + + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct RetrieveLogsRequestRequest { + IntentEnum intent = 0; + TransferProtocolEnum requestedProtocol = 1; + optional char_string<32> transferFileDesignator = 2; + } + + response struct RetrieveLogsResponse = 1 { + StatusEnum status = 0; + long_octet_string logContent = 1; + optional epoch_us UTCTimeStamp = 2; + optional systime_us timeSinceBoot = 3; + } + + /** Retrieving diagnostic logs from a Node */ + command RetrieveLogsRequest(RetrieveLogsRequestRequest): RetrieveLogsResponse = 0; +} + +/** The General Diagnostics Cluster, along with other diagnostics clusters, provide a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ +cluster GeneralDiagnostics = 51 { + revision 2; + + enum BootReasonEnum : enum8 { + kUnspecified = 0; + kPowerOnReboot = 1; + kBrownOutReset = 2; + kSoftwareWatchdogReset = 3; + kHardwareWatchdogReset = 4; + kSoftwareUpdateCompleted = 5; + kSoftwareReset = 6; + } + + enum HardwareFaultEnum : enum8 { + kUnspecified = 0; + kRadio = 1; + kSensor = 2; + kResettableOverTemp = 3; + kNonResettableOverTemp = 4; + kPowerSource = 5; + kVisualDisplayFault = 6; + kAudioOutputFault = 7; + kUserInterfaceFault = 8; + kNonVolatileMemoryError = 9; + kTamperDetected = 10; + } + + enum InterfaceTypeEnum : enum8 { + kUnspecified = 0; + kWiFi = 1; + kEthernet = 2; + kCellular = 3; + kThread = 4; + } + + enum NetworkFaultEnum : enum8 { + kUnspecified = 0; + kHardwareFailure = 1; + kNetworkJammed = 2; + kConnectionFailed = 3; + } + + enum RadioFaultEnum : enum8 { + kUnspecified = 0; + kWiFiFault = 1; + kCellularFault = 2; + kThreadFault = 3; + kNFCFault = 4; + kBLEFault = 5; + kEthernetFault = 6; + } + + bitmap Feature : bitmap32 { + kDataModelTest = 0x1; + } + + struct NetworkInterface { + char_string<32> name = 0; + boolean isOperational = 1; + nullable boolean offPremiseServicesReachableIPv4 = 2; + nullable boolean offPremiseServicesReachableIPv6 = 3; + octet_string<8> hardwareAddress = 4; + octet_string IPv4Addresses[] = 5; + octet_string IPv6Addresses[] = 6; + InterfaceTypeEnum type = 7; + } + + critical event HardwareFaultChange = 0 { + HardwareFaultEnum current[] = 0; + HardwareFaultEnum previous[] = 1; + } + + critical event RadioFaultChange = 1 { + RadioFaultEnum current[] = 0; + RadioFaultEnum previous[] = 1; + } + + critical event NetworkFaultChange = 2 { + NetworkFaultEnum current[] = 0; + NetworkFaultEnum previous[] = 1; + } + + critical event BootReason = 3 { + BootReasonEnum bootReason = 0; + } + + readonly attribute NetworkInterface networkInterfaces[] = 0; + readonly attribute int16u rebootCount = 1; + readonly attribute optional int64u upTime = 2; + readonly attribute optional int32u totalOperationalHours = 3; + readonly attribute optional BootReasonEnum bootReason = 4; + readonly attribute optional HardwareFaultEnum activeHardwareFaults[] = 5; + readonly attribute optional RadioFaultEnum activeRadioFaults[] = 6; + readonly attribute optional NetworkFaultEnum activeNetworkFaults[] = 7; + readonly attribute boolean testEventTriggersEnabled = 8; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct TestEventTriggerRequest { + octet_string<16> enableKey = 0; + int64u eventTrigger = 1; + } + + response struct TimeSnapshotResponse = 2 { + systime_ms systemTimeMs = 0; + nullable posix_ms posixTimeMs = 1; + } + + request struct PayloadTestRequestRequest { + octet_string<16> enableKey = 0; + int8u value = 1; + int16u count = 2; + } + + response struct PayloadTestResponse = 4 { + octet_string payload = 0; + } + + /** Provide a means for certification tests to trigger some test-plan-specific events */ + command access(invoke: manage) TestEventTrigger(TestEventTriggerRequest): DefaultSuccess = 0; + /** Take a snapshot of system time and epoch time. */ + command TimeSnapshot(): TimeSnapshotResponse = 1; + /** Request a variable length payload response. */ + command PayloadTestRequest(PayloadTestRequestRequest): PayloadTestResponse = 3; +} + +/** The Thread Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems */ +cluster ThreadNetworkDiagnostics = 53 { + revision 2; + + enum ConnectionStatusEnum : enum8 { + kConnected = 0; + kNotConnected = 1; + } + + enum NetworkFaultEnum : enum8 { + kUnspecified = 0; + kLinkDown = 1; + kHardwareFailure = 2; + kNetworkJammed = 3; + } + + enum RoutingRoleEnum : enum8 { + kUnspecified = 0; + kUnassigned = 1; + kSleepyEndDevice = 2; + kEndDevice = 3; + kREED = 4; + kRouter = 5; + kLeader = 6; + } + + bitmap Feature : bitmap32 { + kPacketCounts = 0x1; + kErrorCounts = 0x2; + kMLECounts = 0x4; + kMACCounts = 0x8; + } + + struct NeighborTableStruct { + int64u extAddress = 0; + int32u age = 1; + int16u rloc16 = 2; + int32u linkFrameCounter = 3; + int32u mleFrameCounter = 4; + int8u lqi = 5; + nullable int8s averageRssi = 6; + nullable int8s lastRssi = 7; + int8u frameErrorRate = 8; + int8u messageErrorRate = 9; + boolean rxOnWhenIdle = 10; + boolean fullThreadDevice = 11; + boolean fullNetworkData = 12; + boolean isChild = 13; + } + + struct OperationalDatasetComponents { + boolean activeTimestampPresent = 0; + boolean pendingTimestampPresent = 1; + boolean masterKeyPresent = 2; + boolean networkNamePresent = 3; + boolean extendedPanIdPresent = 4; + boolean meshLocalPrefixPresent = 5; + boolean delayPresent = 6; + boolean panIdPresent = 7; + boolean channelPresent = 8; + boolean pskcPresent = 9; + boolean securityPolicyPresent = 10; + boolean channelMaskPresent = 11; + } + + struct RouteTableStruct { + int64u extAddress = 0; + int16u rloc16 = 1; + int8u routerId = 2; + int8u nextHop = 3; + int8u pathCost = 4; + int8u LQIIn = 5; + int8u LQIOut = 6; + int8u age = 7; + boolean allocated = 8; + boolean linkEstablished = 9; + } + + struct SecurityPolicy { + int16u rotationTime = 0; + int16u flags = 1; + } + + info event ConnectionStatus = 0 { + ConnectionStatusEnum connectionStatus = 0; + } + + info event NetworkFaultChange = 1 { + NetworkFaultEnum current[] = 0; + NetworkFaultEnum previous[] = 1; + } + + readonly attribute nullable int16u channel = 0; + readonly attribute nullable RoutingRoleEnum routingRole = 1; + readonly attribute nullable char_string<16> networkName = 2; + readonly attribute nullable int16u panId = 3; + readonly attribute nullable int64u extendedPanId = 4; + readonly attribute nullable octet_string<17> meshLocalPrefix = 5; + readonly attribute optional int64u overrunCount = 6; + readonly attribute NeighborTableStruct neighborTable[] = 7; + readonly attribute RouteTableStruct routeTable[] = 8; + readonly attribute nullable int32u partitionId = 9; + readonly attribute nullable int16u weighting = 10; + readonly attribute nullable int16u dataVersion = 11; + readonly attribute nullable int16u stableDataVersion = 12; + readonly attribute nullable int8u leaderRouterId = 13; + readonly attribute optional int16u detachedRoleCount = 14; + readonly attribute optional int16u childRoleCount = 15; + readonly attribute optional int16u routerRoleCount = 16; + readonly attribute optional int16u leaderRoleCount = 17; + readonly attribute optional int16u attachAttemptCount = 18; + readonly attribute optional int16u partitionIdChangeCount = 19; + readonly attribute optional int16u betterPartitionAttachAttemptCount = 20; + readonly attribute optional int16u parentChangeCount = 21; + readonly attribute optional int32u txTotalCount = 22; + readonly attribute optional int32u txUnicastCount = 23; + readonly attribute optional int32u txBroadcastCount = 24; + readonly attribute optional int32u txAckRequestedCount = 25; + readonly attribute optional int32u txAckedCount = 26; + readonly attribute optional int32u txNoAckRequestedCount = 27; + readonly attribute optional int32u txDataCount = 28; + readonly attribute optional int32u txDataPollCount = 29; + readonly attribute optional int32u txBeaconCount = 30; + readonly attribute optional int32u txBeaconRequestCount = 31; + readonly attribute optional int32u txOtherCount = 32; + readonly attribute optional int32u txRetryCount = 33; + readonly attribute optional int32u txDirectMaxRetryExpiryCount = 34; + readonly attribute optional int32u txIndirectMaxRetryExpiryCount = 35; + readonly attribute optional int32u txErrCcaCount = 36; + readonly attribute optional int32u txErrAbortCount = 37; + readonly attribute optional int32u txErrBusyChannelCount = 38; + readonly attribute optional int32u rxTotalCount = 39; + readonly attribute optional int32u rxUnicastCount = 40; + readonly attribute optional int32u rxBroadcastCount = 41; + readonly attribute optional int32u rxDataCount = 42; + readonly attribute optional int32u rxDataPollCount = 43; + readonly attribute optional int32u rxBeaconCount = 44; + readonly attribute optional int32u rxBeaconRequestCount = 45; + readonly attribute optional int32u rxOtherCount = 46; + readonly attribute optional int32u rxAddressFilteredCount = 47; + readonly attribute optional int32u rxDestAddrFilteredCount = 48; + readonly attribute optional int32u rxDuplicatedCount = 49; + readonly attribute optional int32u rxErrNoFrameCount = 50; + readonly attribute optional int32u rxErrUnknownNeighborCount = 51; + readonly attribute optional int32u rxErrInvalidSrcAddrCount = 52; + readonly attribute optional int32u rxErrSecCount = 53; + readonly attribute optional int32u rxErrFcsCount = 54; + readonly attribute optional int32u rxErrOtherCount = 55; + readonly attribute optional nullable int64u activeTimestamp = 56; + readonly attribute optional nullable int64u pendingTimestamp = 57; + readonly attribute optional nullable int32u delay = 58; + readonly attribute nullable SecurityPolicy securityPolicy = 59; + readonly attribute nullable octet_string<4> channelPage0Mask = 60; + readonly attribute nullable OperationalDatasetComponents operationalDatasetComponents = 61; + readonly attribute NetworkFaultEnum activeNetworkFaultsList[] = 62; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + /** Reception of this command SHALL reset the OverrunCount attributes to 0 */ + command access(invoke: manage) ResetCounts(): DefaultSuccess = 0; +} + +/** The Wi-Fi Network Diagnostics Cluster provides a means to acquire standardized diagnostics metrics that MAY be used by a Node to assist a user or Administrative Node in diagnosing potential problems. */ +cluster WiFiNetworkDiagnostics = 54 { + revision 1; // NOTE: Default/not specifically set + + enum AssociationFailureCauseEnum : enum8 { + kUnknown = 0; + kAssociationFailed = 1; + kAuthenticationFailed = 2; + kSsidNotFound = 3; + } + + enum ConnectionStatusEnum : enum8 { + kConnected = 0; + kNotConnected = 1; + } + + enum SecurityTypeEnum : enum8 { + kUnspecified = 0; + kNone = 1; + kWEP = 2; + kWPA = 3; + kWPA2 = 4; + kWPA3 = 5; + } + + enum WiFiVersionEnum : enum8 { + kA = 0; + kB = 1; + kG = 2; + kN = 3; + kAc = 4; + kAx = 5; + kAh = 6; + } + + bitmap Feature : bitmap32 { + kPacketCounts = 0x1; + kErrorCounts = 0x2; + } + + info event Disconnection = 0 { + int16u reasonCode = 0; + } + + info event AssociationFailure = 1 { + AssociationFailureCauseEnum associationFailureCause = 0; + int16u status = 1; + } + + info event ConnectionStatus = 2 { + ConnectionStatusEnum connectionStatus = 0; + } + + readonly attribute nullable octet_string<6> bssid = 0; + readonly attribute nullable SecurityTypeEnum securityType = 1; + readonly attribute nullable WiFiVersionEnum wiFiVersion = 2; + readonly attribute nullable int16u channelNumber = 3; + readonly attribute nullable int8s rssi = 4; + readonly attribute optional nullable int32u beaconLostCount = 5; + readonly attribute optional nullable int32u beaconRxCount = 6; + readonly attribute optional nullable int32u packetMulticastRxCount = 7; + readonly attribute optional nullable int32u packetMulticastTxCount = 8; + readonly attribute optional nullable int32u packetUnicastRxCount = 9; + readonly attribute optional nullable int32u packetUnicastTxCount = 10; + readonly attribute optional nullable int64u currentMaxRate = 11; + readonly attribute optional nullable int64u overrunCount = 12; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + /** Reception of this command SHALL reset the Breacon and Packet related count attributes to 0 */ + command ResetCounts(): DefaultSuccess = 0; +} + +/** Commands to trigger a Node to allow a new Administrator to commission it. */ +cluster AdministratorCommissioning = 60 { + revision 1; // NOTE: Default/not specifically set + + enum CommissioningWindowStatusEnum : enum8 { + kWindowNotOpen = 0; + kEnhancedWindowOpen = 1; + kBasicWindowOpen = 2; + } + + enum StatusCode : enum8 { + kBusy = 2; + kPAKEParameterError = 3; + kWindowNotOpen = 4; + } + + bitmap Feature : bitmap32 { + kBasic = 0x1; + } + + readonly attribute CommissioningWindowStatusEnum windowStatus = 0; + readonly attribute nullable fabric_idx adminFabricIndex = 1; + readonly attribute nullable vendor_id adminVendorId = 2; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct OpenCommissioningWindowRequest { + int16u commissioningTimeout = 0; + octet_string PAKEPasscodeVerifier = 1; + int16u discriminator = 2; + int32u iterations = 3; + octet_string<32> salt = 4; + } + + request struct OpenBasicCommissioningWindowRequest { + int16u commissioningTimeout = 0; + } + + /** This command is used by a current Administrator to instruct a Node to go into commissioning mode using enhanced commissioning method. */ + timed command access(invoke: administer) OpenCommissioningWindow(OpenCommissioningWindowRequest): DefaultSuccess = 0; + /** This command is used by a current Administrator to instruct a Node to go into commissioning mode using basic commissioning method, if the node supports it. */ + timed command access(invoke: administer) OpenBasicCommissioningWindow(OpenBasicCommissioningWindowRequest): DefaultSuccess = 1; + /** This command is used by a current Administrator to instruct a Node to revoke any active Open Commissioning Window or Open Basic Commissioning Window command. */ + timed command access(invoke: administer) RevokeCommissioning(): DefaultSuccess = 2; +} + +/** This cluster is used to add or remove Operational Credentials on a Commissionee or Node, as well as manage the associated Fabrics. */ +cluster OperationalCredentials = 62 { + revision 1; // NOTE: Default/not specifically set + + enum CertificateChainTypeEnum : enum8 { + kDACCertificate = 1; + kPAICertificate = 2; + } + + enum NodeOperationalCertStatusEnum : enum8 { + kOK = 0; + kInvalidPublicKey = 1; + kInvalidNodeOpId = 2; + kInvalidNOC = 3; + kMissingCsr = 4; + kTableFull = 5; + kInvalidAdminSubject = 6; + kFabricConflict = 9; + kLabelConflict = 10; + kInvalidFabricIndex = 11; + } + + fabric_scoped struct FabricDescriptorStruct { + octet_string<65> rootPublicKey = 1; + vendor_id vendorID = 2; + fabric_id fabricID = 3; + node_id nodeID = 4; + char_string<32> label = 5; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct NOCStruct { + fabric_sensitive octet_string noc = 1; + nullable fabric_sensitive octet_string icac = 2; + fabric_idx fabricIndex = 254; + } + + readonly attribute access(read: administer) NOCStruct NOCs[] = 0; + readonly attribute FabricDescriptorStruct fabrics[] = 1; + readonly attribute int8u supportedFabrics = 2; + readonly attribute int8u commissionedFabrics = 3; + readonly attribute octet_string trustedRootCertificates[] = 4; + readonly attribute int8u currentFabricIndex = 5; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct AttestationRequestRequest { + octet_string<32> attestationNonce = 0; + } + + response struct AttestationResponse = 1 { + octet_string<900> attestationElements = 0; + octet_string<64> attestationSignature = 1; + } + + request struct CertificateChainRequestRequest { + CertificateChainTypeEnum certificateType = 0; + } + + response struct CertificateChainResponse = 3 { + octet_string<600> certificate = 0; + } + + request struct CSRRequestRequest { + octet_string<32> CSRNonce = 0; + optional boolean isForUpdateNOC = 1; + } + + response struct CSRResponse = 5 { + octet_string NOCSRElements = 0; + octet_string attestationSignature = 1; + } + + request struct AddNOCRequest { + octet_string<400> NOCValue = 0; + optional octet_string<400> ICACValue = 1; + octet_string<16> IPKValue = 2; + int64u caseAdminSubject = 3; + vendor_id adminVendorId = 4; + } + + request struct UpdateNOCRequest { + octet_string NOCValue = 0; + optional octet_string ICACValue = 1; + } + + response struct NOCResponse = 8 { + NodeOperationalCertStatusEnum statusCode = 0; + optional fabric_idx fabricIndex = 1; + optional char_string<128> debugText = 2; + } + + request struct UpdateFabricLabelRequest { + char_string<32> label = 0; + } + + request struct RemoveFabricRequest { + fabric_idx fabricIndex = 0; + } + + request struct AddTrustedRootCertificateRequest { + octet_string rootCACertificate = 0; + } + + /** Sender is requesting attestation information from the receiver. */ + command access(invoke: administer) AttestationRequest(AttestationRequestRequest): AttestationResponse = 0; + /** Sender is requesting a device attestation certificate from the receiver. */ + command access(invoke: administer) CertificateChainRequest(CertificateChainRequestRequest): CertificateChainResponse = 2; + /** Sender is requesting a certificate signing request (CSR) from the receiver. */ + command access(invoke: administer) CSRRequest(CSRRequestRequest): CSRResponse = 4; + /** Sender is requesting to add the new node operational certificates. */ + command access(invoke: administer) AddNOC(AddNOCRequest): NOCResponse = 6; + /** Sender is requesting to update the node operational certificates. */ + fabric command access(invoke: administer) UpdateNOC(UpdateNOCRequest): NOCResponse = 7; + /** This command SHALL be used by an Administrative Node to set the user-visible Label field for a given Fabric, as reflected by entries in the Fabrics attribute. */ + fabric command access(invoke: administer) UpdateFabricLabel(UpdateFabricLabelRequest): NOCResponse = 9; + /** This command is used by Administrative Nodes to remove a given fabric index and delete all associated fabric-scoped data. */ + command access(invoke: administer) RemoveFabric(RemoveFabricRequest): NOCResponse = 10; + /** This command SHALL add a Trusted Root CA Certificate, provided as its CHIP Certificate representation. */ + command access(invoke: administer) AddTrustedRootCertificate(AddTrustedRootCertificateRequest): DefaultSuccess = 11; +} + +/** The Group Key Management Cluster is the mechanism by which group keys are managed. */ +cluster GroupKeyManagement = 63 { + revision 1; // NOTE: Default/not specifically set + + enum GroupKeySecurityPolicyEnum : enum8 { + kTrustFirst = 0; + kCacheAndSync = 1; + } + + bitmap Feature : bitmap32 { + kCacheAndSync = 0x1; + } + + fabric_scoped struct GroupInfoMapStruct { + group_id groupId = 1; + endpoint_no endpoints[] = 2; + optional char_string<16> groupName = 3; + fabric_idx fabricIndex = 254; + } + + fabric_scoped struct GroupKeyMapStruct { + group_id groupId = 1; + int16u groupKeySetID = 2; + fabric_idx fabricIndex = 254; + } + + struct GroupKeySetStruct { + int16u groupKeySetID = 0; + GroupKeySecurityPolicyEnum groupKeySecurityPolicy = 1; + nullable octet_string<16> epochKey0 = 2; + nullable epoch_us epochStartTime0 = 3; + nullable octet_string<16> epochKey1 = 4; + nullable epoch_us epochStartTime1 = 5; + nullable octet_string<16> epochKey2 = 6; + nullable epoch_us epochStartTime2 = 7; + } + + attribute access(write: manage) GroupKeyMapStruct groupKeyMap[] = 0; + readonly attribute GroupInfoMapStruct groupTable[] = 1; + readonly attribute int16u maxGroupsPerFabric = 2; + readonly attribute int16u maxGroupKeysPerFabric = 3; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct KeySetWriteRequest { + GroupKeySetStruct groupKeySet = 0; + } + + request struct KeySetReadRequest { + int16u groupKeySetID = 0; + } + + response struct KeySetReadResponse = 2 { + GroupKeySetStruct groupKeySet = 0; + } + + request struct KeySetRemoveRequest { + int16u groupKeySetID = 0; + } + + response struct KeySetReadAllIndicesResponse = 5 { + int16u groupKeySetIDs[] = 0; + } + + /** Write a new set of keys for the given key set id. */ + fabric command access(invoke: administer) KeySetWrite(KeySetWriteRequest): DefaultSuccess = 0; + /** Read the keys for a given key set id. */ + fabric command access(invoke: administer) KeySetRead(KeySetReadRequest): KeySetReadResponse = 1; + /** Revoke a Root Key from a Group */ + fabric command access(invoke: administer) KeySetRemove(KeySetRemoveRequest): DefaultSuccess = 3; + /** Return the list of Group Key Sets associated with the accessing fabric */ + fabric command access(invoke: administer) KeySetReadAllIndices(): KeySetReadAllIndicesResponse = 4; +} + +/** The Fixed Label Cluster provides a feature for the device to tag an endpoint with zero or more read only +labels. */ +cluster FixedLabel = 64 { + revision 1; // NOTE: Default/not specifically set + + struct LabelStruct { + char_string<16> label = 0; + char_string<16> value = 1; + } + + readonly attribute LabelStruct labelList[] = 0; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** The User Label Cluster provides a feature to tag an endpoint with zero or more labels. */ +cluster UserLabel = 65 { + revision 1; // NOTE: Default/not specifically set + + struct LabelStruct { + char_string<16> label = 0; + char_string<16> value = 1; + } + + attribute access(write: manage) LabelStruct labelList[] = 0; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; +} + +/** An interface for configuring and controlling the functionality of a thermostat. */ +cluster Thermostat = 513 { + revision 7; + + enum ACCapacityFormatEnum : enum8 { + kBTUh = 0; + } + + enum ACCompressorTypeEnum : enum8 { + kUnknown = 0; + kT1 = 1; + kT2 = 2; + kT3 = 3; + } + + enum ACLouverPositionEnum : enum8 { + kClosed = 1; + kOpen = 2; + kQuarter = 3; + kHalf = 4; + kThreeQuarters = 5; + } + + enum ACRefrigerantTypeEnum : enum8 { + kUnknown = 0; + kR22 = 1; + kR410a = 2; + kR407c = 3; + } + + enum ACTypeEnum : enum8 { + kUnknown = 0; + kCoolingFixed = 1; + kHeatPumpFixed = 2; + kCoolingInverter = 3; + kHeatPumpInverter = 4; + } + + enum ControlSequenceOfOperationEnum : enum8 { + kCoolingOnly = 0; + kCoolingWithReheat = 1; + kHeatingOnly = 2; + kHeatingWithReheat = 3; + kCoolingAndHeating = 4; + kCoolingAndHeatingWithReheat = 5; + } + + enum PresetScenarioEnum : enum8 { + kOccupied = 1; + kUnoccupied = 2; + kSleep = 3; + kWake = 4; + kVacation = 5; + kGoingToSleep = 6; + kUserDefined = 254; + } + + enum SetpointChangeSourceEnum : enum8 { + kManual = 0; + kSchedule = 1; + kExternal = 2; + } + + enum SetpointRaiseLowerModeEnum : enum8 { + kHeat = 0; + kCool = 1; + kBoth = 2; + } + + enum StartOfWeekEnum : enum8 { + kSunday = 0; + kMonday = 1; + kTuesday = 2; + kWednesday = 3; + kThursday = 4; + kFriday = 5; + kSaturday = 6; + } + + enum SystemModeEnum : enum8 { + kOff = 0; + kAuto = 1; + kCool = 3; + kHeat = 4; + kEmergencyHeat = 5; + kPrecooling = 6; + kFanOnly = 7; + kDry = 8; + kSleep = 9; + } + + enum TemperatureSetpointHoldEnum : enum8 { + kSetpointHoldOff = 0; + kSetpointHoldOn = 1; + } + + enum ThermostatRunningModeEnum : enum8 { + kOff = 0; + kCool = 3; + kHeat = 4; + } + + bitmap ACErrorCodeBitmap : bitmap32 { + kCompressorFail = 0x1; + kRoomSensorFail = 0x2; + kOutdoorSensorFail = 0x4; + kCoilSensorFail = 0x8; + kFanFail = 0x10; + } + + bitmap Feature : bitmap32 { + kHeating = 0x1; + kCooling = 0x2; + kOccupancy = 0x4; + kScheduleConfiguration = 0x8; + kSetback = 0x10; + kAutoMode = 0x20; + kLocalTemperatureNotExposed = 0x40; + kMatterScheduleConfiguration = 0x80; + kPresets = 0x100; + } + + bitmap HVACSystemTypeBitmap : bitmap8 { + kCoolingStage = 0x3; + kHeatingStage = 0xC; + kHeatingIsHeatPump = 0x10; + kHeatingUsesFuel = 0x20; + } + + bitmap OccupancyBitmap : bitmap8 { + kOccupied = 0x1; + } + + bitmap PresetTypeFeaturesBitmap : bitmap16 { + kAutomatic = 0x1; + kSupportsNames = 0x2; + } + + bitmap ProgrammingOperationModeBitmap : bitmap8 { + kScheduleActive = 0x1; + kAutoRecovery = 0x2; + kEconomy = 0x4; + } + + bitmap RelayStateBitmap : bitmap16 { + kHeat = 0x1; + kCool = 0x2; + kFan = 0x4; + kHeatStage2 = 0x8; + kCoolStage2 = 0x10; + kFanStage2 = 0x20; + kFanStage3 = 0x40; + } + + bitmap RemoteSensingBitmap : bitmap8 { + kLocalTemperature = 0x1; + kOutdoorTemperature = 0x2; + kOccupancy = 0x4; + } + + bitmap ScheduleDayOfWeekBitmap : bitmap8 { + kSunday = 0x1; + kMonday = 0x2; + kTuesday = 0x4; + kWednesday = 0x8; + kThursday = 0x10; + kFriday = 0x20; + kSaturday = 0x40; + kAway = 0x80; + } + + bitmap ScheduleModeBitmap : bitmap8 { + kHeatSetpointPresent = 0x1; + kCoolSetpointPresent = 0x2; + } + + bitmap ScheduleTypeFeaturesBitmap : bitmap16 { + kSupportsPresets = 0x1; + kSupportsSetpoints = 0x2; + kSupportsNames = 0x4; + kSupportsOff = 0x8; + } + + struct ScheduleTransitionStruct { + ScheduleDayOfWeekBitmap dayOfWeek = 0; + int16u transitionTime = 1; + optional octet_string<16> presetHandle = 2; + optional SystemModeEnum systemMode = 3; + optional temperature coolingSetpoint = 4; + optional temperature heatingSetpoint = 5; + } + + struct ScheduleStruct { + nullable octet_string<16> scheduleHandle = 0; + SystemModeEnum systemMode = 1; + optional char_string<64> name = 2; + optional octet_string<16> presetHandle = 3; + ScheduleTransitionStruct transitions[] = 4; + nullable boolean builtIn = 5; + } + + struct PresetStruct { + nullable octet_string<16> presetHandle = 0; + PresetScenarioEnum presetScenario = 1; + optional nullable char_string<64> name = 2; + optional temperature coolingSetpoint = 3; + optional temperature heatingSetpoint = 4; + nullable boolean builtIn = 5; + } + + struct PresetTypeStruct { + PresetScenarioEnum presetScenario = 0; + int8u numberOfPresets = 1; + PresetTypeFeaturesBitmap presetTypeFeatures = 2; + } + + struct ScheduleTypeStruct { + SystemModeEnum systemMode = 0; + int8u numberOfSchedules = 1; + ScheduleTypeFeaturesBitmap scheduleTypeFeatures = 2; + } + + struct WeeklyScheduleTransitionStruct { + int16u transitionTime = 0; + nullable temperature heatSetpoint = 1; + nullable temperature coolSetpoint = 2; + } + + readonly attribute nullable temperature localTemperature = 0; + readonly attribute optional nullable temperature outdoorTemperature = 1; + readonly attribute optional OccupancyBitmap occupancy = 2; + readonly attribute optional temperature absMinHeatSetpointLimit = 3; + readonly attribute optional temperature absMaxHeatSetpointLimit = 4; + readonly attribute optional temperature absMinCoolSetpointLimit = 5; + readonly attribute optional temperature absMaxCoolSetpointLimit = 6; + readonly attribute optional int8u PICoolingDemand = 7; + readonly attribute optional int8u PIHeatingDemand = 8; + attribute access(write: manage) optional HVACSystemTypeBitmap HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional int8s localTemperatureCalibration = 16; + attribute optional temperature occupiedCoolingSetpoint = 17; + attribute optional temperature occupiedHeatingSetpoint = 18; + attribute optional temperature unoccupiedCoolingSetpoint = 19; + attribute optional temperature unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional temperature minHeatSetpointLimit = 21; + attribute access(write: manage) optional temperature maxHeatSetpointLimit = 22; + attribute access(write: manage) optional temperature minCoolSetpointLimit = 23; + attribute access(write: manage) optional temperature maxCoolSetpointLimit = 24; + attribute access(write: manage) optional int8s minSetpointDeadBand = 25; + attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; + attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; + attribute access(write: manage) SystemModeEnum systemMode = 28; + readonly attribute optional ThermostatRunningModeEnum thermostatRunningMode = 30; + readonly attribute optional StartOfWeekEnum startOfWeek = 32; + readonly attribute optional int8u numberOfWeeklyTransitions = 33; + readonly attribute optional int8u numberOfDailyTransitions = 34; + attribute access(write: manage) optional TemperatureSetpointHoldEnum temperatureSetpointHold = 35; + attribute access(write: manage) optional nullable int16u temperatureSetpointHoldDuration = 36; + attribute access(write: manage) optional ProgrammingOperationModeBitmap thermostatProgrammingOperationMode = 37; + readonly attribute optional RelayStateBitmap thermostatRunningState = 41; + readonly attribute optional SetpointChangeSourceEnum setpointChangeSource = 48; + readonly attribute optional nullable int16s setpointChangeAmount = 49; + readonly attribute optional epoch_s setpointChangeSourceTimestamp = 50; + attribute access(write: manage) optional nullable int8u occupiedSetback = 52; + readonly attribute optional nullable int8u occupiedSetbackMin = 53; + readonly attribute optional nullable int8u occupiedSetbackMax = 54; + attribute access(write: manage) optional nullable int8u unoccupiedSetback = 55; + readonly attribute optional nullable int8u unoccupiedSetbackMin = 56; + readonly attribute optional nullable int8u unoccupiedSetbackMax = 57; + attribute access(write: manage) optional int8u emergencyHeatDelta = 58; + attribute access(write: manage) optional ACTypeEnum ACType = 64; + attribute access(write: manage) optional int16u ACCapacity = 65; + attribute access(write: manage) optional ACRefrigerantTypeEnum ACRefrigerantType = 66; + attribute access(write: manage) optional ACCompressorTypeEnum ACCompressorType = 67; + attribute access(write: manage) optional ACErrorCodeBitmap ACErrorCode = 68; + attribute access(write: manage) optional ACLouverPositionEnum ACLouverPosition = 69; + readonly attribute optional nullable temperature ACCoilTemperature = 70; + attribute access(write: manage) optional ACCapacityFormatEnum ACCapacityformat = 71; + readonly attribute optional PresetTypeStruct presetTypes[] = 72; + readonly attribute optional ScheduleTypeStruct scheduleTypes[] = 73; + readonly attribute optional int8u numberOfPresets = 74; + readonly attribute optional int8u numberOfSchedules = 75; + readonly attribute optional int8u numberOfScheduleTransitions = 76; + readonly attribute optional nullable int8u numberOfScheduleTransitionPerDay = 77; + readonly attribute optional nullable octet_string<16> activePresetHandle = 78; + readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; + attribute access(write: manage) optional PresetStruct presets[] = 80; + attribute access(write: manage) optional ScheduleStruct schedules[] = 81; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 82; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct SetpointRaiseLowerRequest { + SetpointRaiseLowerModeEnum mode = 0; + int8s amount = 1; + } + + response struct GetWeeklyScheduleResponse = 0 { + int8u numberOfTransitionsForSequence = 0; + ScheduleDayOfWeekBitmap dayOfWeekForSequence = 1; + ScheduleModeBitmap modeForSequence = 2; + WeeklyScheduleTransitionStruct transitions[] = 3; + } + + request struct SetWeeklyScheduleRequest { + int8u numberOfTransitionsForSequence = 0; + ScheduleDayOfWeekBitmap dayOfWeekForSequence = 1; + ScheduleModeBitmap modeForSequence = 2; + WeeklyScheduleTransitionStruct transitions[] = 3; + } + + request struct GetWeeklyScheduleRequest { + ScheduleDayOfWeekBitmap daysToReturn = 0; + ScheduleModeBitmap modeToReturn = 1; + } + + request struct SetActiveScheduleRequestRequest { + octet_string<16> scheduleHandle = 0; + } + + request struct SetActivePresetRequestRequest { + nullable octet_string<16> presetHandle = 0; + } + + response struct AtomicResponse = 253 { + status statusCode = 0; + AtomicAttributeStatusStruct attributeStatus[] = 1; + optional int16u timeout = 2; + } + + request struct AtomicRequestRequest { + AtomicRequestTypeEnum requestType = 0; + attrib_id attributeRequests[] = 1; + optional int16u timeout = 2; + } + + /** Upon receipt, the attributes for the indicated setpoint(s) SHALL have the amount specified in the Amount field added to them. */ + command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; + /** This command is used to update the thermostat weekly setpoint schedule from a management system. */ + command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; + /** The Current Weekly Schedule Command is sent from the server in response to the Get Weekly Schedule Command. */ + command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; + /** This command is used to clear the weekly schedule. */ + command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; + /** Upon receipt, if the Schedules attribute contains a ScheduleStruct whose ScheduleHandle field matches the value of the ScheduleHandle field, the server SHALL set the thermostat's ActiveScheduleHandle attribute to the value of the ScheduleHandle field. */ + command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; + /** ID */ + command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; + /** Begins, Commits or Cancels an atomic write */ + command access(invoke: manage) AtomicRequest(AtomicRequestRequest): AtomicResponse = 254; +} + +/** Manage the Thread network of Thread Border Router */ +provisional cluster ThreadBorderRouterManagement = 1106 { + revision 1; + + bitmap Feature : bitmap32 { + kPANChange = 0x1; + } + + provisional readonly attribute char_string<63> borderRouterName = 0; + provisional readonly attribute octet_string<254> borderAgentID = 1; + provisional readonly attribute int16u threadVersion = 2; + provisional readonly attribute boolean interfaceEnabled = 3; + provisional readonly attribute nullable int64u activeDatasetTimestamp = 4; + provisional readonly attribute nullable int64u pendingDatasetTimestamp = 5; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + response struct DatasetResponse = 2 { + octet_string<254> dataset = 0; + } + + request struct SetActiveDatasetRequestRequest { + octet_string<254> activeDataset = 0; + optional int64u breadcrumb = 1; + } + + request struct SetPendingDatasetRequestRequest { + octet_string<254> pendingDataset = 0; + } + + /** Command to request the active operational dataset of the Thread network to which the border router is connected. This command must be sent over a valid CASE session */ + command access(invoke: manage) GetActiveDatasetRequest(): DatasetResponse = 0; + /** Command to request the pending dataset of the Thread network to which the border router is connected. This command must be sent over a valid CASE session */ + command access(invoke: manage) GetPendingDatasetRequest(): DatasetResponse = 1; + /** Command to set or update the active Dataset of the Thread network to which the Border Router is connected. */ + command access(invoke: manage) SetActiveDatasetRequest(SetActiveDatasetRequestRequest): DefaultSuccess = 3; + /** Command set or update the pending Dataset of the Thread network to which the Border Router is connected. */ + command access(invoke: manage) SetPendingDatasetRequest(SetPendingDatasetRequestRequest): DefaultSuccess = 4; +} + +endpoint 0 { + device type ma_rootdevice = 22, version 1; + + binding cluster OtaSoftwareUpdateProvider; + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster AccessControl { + emits event AccessControlEntryChanged; + emits event AccessControlExtensionChanged; + callback attribute acl; + callback attribute extension; + callback attribute subjectsPerAccessControlEntry; + callback attribute targetsPerAccessControlEntry; + callback attribute accessControlEntriesPerFabric; + callback attribute attributeList; + ram attribute featureMap default = 0; + callback attribute clusterRevision; + } + + server cluster BasicInformation { + emits event StartUp; + emits event ShutDown; + emits event Leave; + callback attribute dataModelRevision; + callback attribute vendorName; + callback attribute vendorID; + callback attribute productName; + callback attribute productID; + persist attribute nodeLabel; + callback attribute location; + callback attribute hardwareVersion; + callback attribute hardwareVersionString; + callback attribute softwareVersion; + callback attribute softwareVersionString; + callback attribute manufacturingDate; + callback attribute partNumber; + callback attribute productURL; + callback attribute productLabel; + callback attribute serialNumber; + persist attribute localConfigDisabled default = 0; + callback attribute uniqueID; + callback attribute capabilityMinima; + callback attribute specificationVersion; + callback attribute maxPathsPerInvoke; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 3; + } + + server cluster OtaSoftwareUpdateRequestor { + emits event StateTransition; + emits event VersionApplied; + emits event DownloadError; + callback attribute defaultOTAProviders; + ram attribute updatePossible default = 1; + ram attribute updateState default = 0; + ram attribute updateStateProgress default = 0; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command AnnounceOTAProvider; + } + + server cluster LocalizationConfiguration { + persist attribute activeLocale default = "en-US"; + callback attribute supportedLocales; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster TimeFormatLocalization { + persist attribute hourFormat default = 0; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster UnitLocalization { + ram attribute temperatureUnit; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0x1; + ram attribute clusterRevision default = 1; + } + + server cluster GeneralCommissioning { + ram attribute breadcrumb default = 0x0000000000000000; + callback attribute basicCommissioningInfo; + callback attribute regulatoryConfig; + callback attribute locationCapability; + callback attribute supportsConcurrentConnection; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command ArmFailSafe; + handle command ArmFailSafeResponse; + handle command SetRegulatoryConfig; + handle command SetRegulatoryConfigResponse; + handle command CommissioningComplete; + handle command CommissioningCompleteResponse; + } + + server cluster NetworkCommissioning { + ram attribute maxNetworks; + callback attribute networks; + ram attribute scanMaxTimeSeconds; + ram attribute connectMaxTimeSeconds; + ram attribute interfaceEnabled; + ram attribute lastNetworkingStatus; + ram attribute lastNetworkID; + ram attribute lastConnectErrorValue; + callback attribute supportedWiFiBands; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 1; + ram attribute clusterRevision default = 1; + + handle command ScanNetworks; + handle command ScanNetworksResponse; + handle command AddOrUpdateWiFiNetwork; + handle command AddOrUpdateThreadNetwork; + handle command RemoveNetwork; + handle command NetworkConfigResponse; + handle command ConnectNetwork; + handle command ConnectNetworkResponse; + handle command ReorderNetwork; + } + + server cluster DiagnosticLogs { + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command RetrieveLogsRequest; + handle command RetrieveLogsResponse; + } + + server cluster GeneralDiagnostics { + emits event BootReason; + callback attribute networkInterfaces; + callback attribute rebootCount; + callback attribute upTime; + callback attribute totalOperationalHours; + callback attribute bootReason; + callback attribute testEventTriggersEnabled default = false; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command TestEventTrigger; + handle command TimeSnapshot; + handle command TimeSnapshotResponse; + } + + server cluster WiFiNetworkDiagnostics { + callback attribute bssid; + callback attribute securityType; + callback attribute wiFiVersion; + callback attribute channelNumber; + callback attribute rssi; + callback attribute currentMaxRate; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster AdministratorCommissioning { + callback attribute windowStatus; + callback attribute adminFabricIndex; + callback attribute adminVendorId; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command OpenCommissioningWindow; + handle command RevokeCommissioning; + } + + server cluster OperationalCredentials { + callback attribute NOCs; + callback attribute fabrics; + callback attribute supportedFabrics; + callback attribute commissionedFabrics; + callback attribute trustedRootCertificates; + callback attribute currentFabricIndex; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command AttestationRequest; + handle command AttestationResponse; + handle command CertificateChainRequest; + handle command CertificateChainResponse; + handle command CSRRequest; + handle command CSRResponse; + handle command AddNOC; + handle command UpdateNOC; + handle command NOCResponse; + handle command UpdateFabricLabel; + handle command RemoveFabric; + handle command AddTrustedRootCertificate; + } + + server cluster GroupKeyManagement { + callback attribute groupKeyMap; + callback attribute groupTable; + callback attribute maxGroupsPerFabric; + callback attribute maxGroupKeysPerFabric; + callback attribute featureMap; + callback attribute clusterRevision; + + handle command KeySetWrite; + handle command KeySetRead; + handle command KeySetReadResponse; + handle command KeySetRemove; + handle command KeySetReadAllIndices; + handle command KeySetReadAllIndicesResponse; + } +} +endpoint 1 { + device type ma_thermostat = 769, version 1; + + binding cluster Identify; + + server cluster Identify { + ram attribute identifyTime default = 0x0000; + ram attribute identifyType default = 0x0; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 4; + + handle command Identify; + handle command TriggerEffect; + } + + server cluster Groups { + ram attribute nameSupport; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 4; + + handle command AddGroup; + handle command AddGroupResponse; + handle command ViewGroup; + handle command ViewGroupResponse; + handle command GetGroupMembership; + handle command GetGroupMembershipResponse; + handle command RemoveGroup; + handle command RemoveGroupResponse; + handle command RemoveAllGroups; + handle command AddGroupIfIdentifying; + } + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster Binding { + callback attribute binding; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster FixedLabel { + callback attribute labelList; + callback attribute eventList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster UserLabel { + callback attribute labelList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + } + + server cluster Thermostat { + ram attribute localTemperature; + ram attribute absMinHeatSetpointLimit default = 700; + ram attribute absMaxHeatSetpointLimit default = 3000; + ram attribute absMinCoolSetpointLimit default = 1600; + ram attribute absMaxCoolSetpointLimit default = 3200; + persist attribute occupiedCoolingSetpoint default = 0x0A28; + persist attribute occupiedHeatingSetpoint default = 0x07D0; + ram attribute minHeatSetpointLimit default = 700; + ram attribute maxHeatSetpointLimit default = 3000; + ram attribute minCoolSetpointLimit default = 1600; + ram attribute maxCoolSetpointLimit default = 3200; + ram attribute controlSequenceOfOperation default = 0x04; + persist attribute systemMode default = 0x01; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute attributeList; + ram attribute featureMap default = 0x3; + ram attribute clusterRevision default = 7; + + handle command SetpointRaiseLower; + } +} +endpoint 2 { + device type ma_thread_border_router = 145, version 1; + + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster ThreadNetworkDiagnostics { + callback attribute channel; + callback attribute routingRole; + callback attribute networkName; + callback attribute panId; + callback attribute extendedPanId; + callback attribute meshLocalPrefix; + callback attribute neighborTable; + callback attribute routeTable; + callback attribute partitionId; + callback attribute weighting; + callback attribute dataVersion; + callback attribute stableDataVersion; + callback attribute leaderRouterId; + callback attribute securityPolicy; + callback attribute channelPage0Mask; + callback attribute operationalDatasetComponents; + callback attribute activeNetworkFaultsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 2; + } + + server cluster ThreadBorderRouterManagement { + callback attribute borderRouterName; + callback attribute borderAgentID; + callback attribute threadVersion; + callback attribute interfaceEnabled; + callback attribute activeDatasetTimestamp; + callback attribute pendingDatasetTimestamp; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + ram attribute clusterRevision default = 1; + + handle command GetActiveDatasetRequest; + handle command GetPendingDatasetRequest; + handle command DatasetResponse; + handle command SetActiveDatasetRequest; + handle command SetPendingDatasetRequest; + } +} +endpoint 3 { + device type ma_secondary_network_interface = 25, version 1; + + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster NetworkCommissioning { + ram attribute maxNetworks; + callback attribute networks; + ram attribute scanMaxTimeSeconds; + ram attribute connectMaxTimeSeconds; + ram attribute interfaceEnabled; + ram attribute lastNetworkingStatus; + ram attribute lastNetworkID; + ram attribute lastConnectErrorValue; + ram attribute supportedThreadFeatures; + ram attribute threadVersion; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 1; + + handle command ScanNetworks; + handle command ScanNetworksResponse; + handle command AddOrUpdateThreadNetwork; + handle command RemoveNetwork; + handle command NetworkConfigResponse; + handle command ConnectNetwork; + handle command ConnectNetworkResponse; + handle command ReorderNetwork; + } +} + + diff --git a/examples/thermostat/nxp/zap/thermostat_matter_br.zap b/examples/thermostat/nxp/zap/thermostat_matter_br.zap new file mode 100644 index 00000000000000..3586eeb6b2320d --- /dev/null +++ b/examples/thermostat/nxp/zap/thermostat_matter_br.zap @@ -0,0 +1,5392 @@ +{ + "fileFormat": 2, + "featureLevel": 103, + "creator": "zap", + "keyValuePairs": [ + { + "key": "commandDiscovery", + "value": "1" + }, + { + "key": "defaultResponsePolicy", + "value": "always" + }, + { + "key": "manufacturerCodes", + "value": "0x1002" + } + ], + "package": [ + { + "pathRelativity": "relativeToZap", + "path": "../../../../src/app/zap-templates/zcl/zcl.json", + "type": "zcl-properties", + "category": "matter", + "version": 1, + "description": "Matter SDK ZCL data" + }, + { + "pathRelativity": "relativeToZap", + "path": "../../../../src/app/zap-templates/app-templates.json", + "type": "gen-templates-json", + "category": "matter", + "version": "chip-v1" + } + ], + "endpointTypes": [ + { + "id": 1, + "name": "MA-rootdevice", + "deviceTypeRef": { + "code": 22, + "profileId": 259, + "label": "MA-rootdevice", + "name": "MA-rootdevice" + }, + "deviceTypes": [ + { + "code": 22, + "profileId": 259, + "label": "MA-rootdevice", + "name": "MA-rootdevice" + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 22 + ], + "deviceTypeName": "MA-rootdevice", + "deviceTypeCode": 22, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Access Control", + "code": 31, + "mfgCode": null, + "define": "ACCESS_CONTROL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "ACL", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Extension", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SubjectsPerAccessControlEntry", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TargetsPerAccessControlEntry", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AccessControlEntriesPerFabric", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "AccessControlEntryChanged", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "AccessControlExtensionChanged", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Basic Information", + "code": 40, + "mfgCode": null, + "define": "BASIC_INFORMATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DataModelRevision", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "VendorName", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "VendorID", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductName", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductID", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "NodeLabel", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "NVM", + "singleton": 1, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "Location", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "HardwareVersion", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "HardwareVersionString", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SoftwareVersion", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SoftwareVersionString", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ManufacturingDate", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "PartNumber", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductURL", + "code": 13, + "mfgCode": null, + "side": "server", + "type": "long_char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ProductLabel", + "code": 14, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SerialNumber", + "code": 15, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "LocalConfigDisabled", + "code": 16, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "NVM", + "singleton": 1, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "UniqueID", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CapabilityMinima", + "code": 19, + "mfgCode": null, + "side": "server", + "type": "CapabilityMinimaStruct", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SpecificationVersion", + "code": 21, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxPathsPerInvoke", + "code": 22, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 1, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 1, + "bounded": 0, + "defaultValue": "3", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "StartUp", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "ShutDown", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "Leave", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "OTA Software Update Provider", + "code": 41, + "mfgCode": null, + "define": "OTA_SOFTWARE_UPDATE_PROVIDER_CLUSTER", + "side": "client", + "enabled": 1, + "commands": [ + { + "name": "QueryImage", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "QueryImageResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ApplyUpdateRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ApplyUpdateResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NotifyUpdateApplied", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + } + ] + }, + { + "name": "OTA Software Update Requestor", + "code": 42, + "mfgCode": null, + "define": "OTA_SOFTWARE_UPDATE_REQUESTOR_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AnnounceOTAProvider", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "DefaultOTAProviders", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UpdatePossible", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UpdateState", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "UpdateStateEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "UpdateStateProgress", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "StateTransition", + "code": 0, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "VersionApplied", + "code": 1, + "mfgCode": null, + "side": "server", + "included": 1 + }, + { + "name": "DownloadError", + "code": 2, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Localization Configuration", + "code": 43, + "mfgCode": null, + "define": "LOCALIZATION_CONFIGURATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "ActiveLocale", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "en-US", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedLocales", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Time Format Localization", + "code": 44, + "mfgCode": null, + "define": "TIME_FORMAT_LOCALIZATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "HourFormat", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "HourFormatEnum", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Unit Localization", + "code": 45, + "mfgCode": null, + "define": "UNIT_LOCALIZATION_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "TemperatureUnit", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "TempUnitEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "General Commissioning", + "code": 48, + "mfgCode": null, + "define": "GENERAL_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ArmFailSafe", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ArmFailSafeResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "SetRegulatoryConfig", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SetRegulatoryConfigResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CommissioningComplete", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CommissioningCompleteResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "Breadcrumb", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000000000000000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "BasicCommissioningInfo", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "BasicCommissioningInfo", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RegulatoryConfig", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LocationCapability", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "RegulatoryLocationTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportsConcurrentConnection", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Network Commissioning", + "code": 49, + "mfgCode": null, + "define": "NETWORK_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ScanNetworks", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ScanNetworksResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AddOrUpdateWiFiNetwork", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddOrUpdateThreadNetwork", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveNetwork", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NetworkConfigResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ConnectNetwork", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ConnectNetworkResponse", + "code": 7, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ReorderNetwork", + "code": 8, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "MaxNetworks", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Networks", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ScanMaxTimeSeconds", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ConnectMaxTimeSeconds", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "InterfaceEnabled", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkingStatus", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "NetworkCommissioningStatusEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkID", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastConnectErrorValue", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int32s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedWiFiBands", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Diagnostic Logs", + "code": 50, + "mfgCode": null, + "define": "DIAGNOSTIC_LOGS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "RetrieveLogsRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RetrieveLogsResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "General Diagnostics", + "code": 51, + "mfgCode": null, + "define": "GENERAL_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "TestEventTrigger", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TimeSnapshot", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TimeSnapshotResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NetworkInterfaces", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RebootCount", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "UpTime", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TotalOperationalHours", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BootReason", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "BootReasonEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "TestEventTriggersEnabled", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "false", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ], + "events": [ + { + "name": "BootReason", + "code": 3, + "mfgCode": null, + "side": "server", + "included": 1 + } + ] + }, + { + "name": "Wi-Fi Network Diagnostics", + "code": 54, + "mfgCode": null, + "define": "WIFI_NETWORK_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "BSSID", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SecurityType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "SecurityTypeEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "WiFiVersion", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "WiFiVersionEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ChannelNumber", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "RSSI", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int8s", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentMaxRate", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Administrator Commissioning", + "code": 60, + "mfgCode": null, + "define": "ADMINISTRATOR_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "OpenCommissioningWindow", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RevokeCommissioning", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "WindowStatus", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "CommissioningWindowStatusEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminFabricIndex", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "fabric_idx", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AdminVendorId", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "vendor_id", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Operational Credentials", + "code": 62, + "mfgCode": null, + "define": "OPERATIONAL_CREDENTIALS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AttestationRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AttestationResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CertificateChainRequest", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CertificateChainResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "CSRRequest", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "CSRResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AddNOC", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "UpdateNOC", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NOCResponse", + "code": 8, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "UpdateFabricLabel", + "code": 9, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveFabric", + "code": 10, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddTrustedRootCertificate", + "code": 11, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NOCs", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Fabrics", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SupportedFabrics", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CommissionedFabrics", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "TrustedRootCertificates", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "CurrentFabricIndex", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Group Key Management", + "code": 63, + "mfgCode": null, + "define": "GROUP_KEY_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "KeySetWrite", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetRead", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "KeySetRemove", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndices", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "KeySetReadAllIndicesResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "GroupKeyMap", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "GroupTable", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MaxGroupsPerFabric", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MaxGroupKeysPerFabric", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + } + ] + }, + { + "id": 2, + "name": "MA-thermostat", + "deviceTypeRef": { + "code": 769, + "profileId": 259, + "label": "MA-thermostat", + "name": "MA-thermostat" + }, + "deviceTypes": [ + { + "code": 769, + "profileId": 259, + "label": "MA-thermostat", + "name": "MA-thermostat" + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 769 + ], + "deviceTypeName": "MA-thermostat", + "deviceTypeCode": 769, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "client", + "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 0, + "isEnabled": 1 + } + ] + }, + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "IdentifyTime", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "IdentifyType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "IdentifyTypeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Groups", + "code": 4, + "mfgCode": null, + "define": "GROUPS_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "AddGroup", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddGroupResponse", + "code": 0, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ViewGroup", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ViewGroupResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "GetGroupMembership", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "GetGroupMembershipResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "RemoveGroup", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveGroupResponse", + "code": 3, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "RemoveAllGroups", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "AddGroupIfIdentifying", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "NameSupport", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "NameSupportBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Binding", + "code": 30, + "mfgCode": null, + "define": "BINDING_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "Binding", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "Fixed Label", + "code": 64, + "mfgCode": null, + "define": "FIXED_LABEL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "LabelList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + }, + { + "name": "User Label", + "code": 65, + "mfgCode": null, + "define": "USER_LABEL_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "LabelList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Thermostat", + "code": 513, + "mfgCode": null, + "define": "THERMOSTAT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "SetpointRaiseLower", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "LocalTemperature", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "AbsMinHeatSetpointLimit", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "700", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "AbsMaxHeatSetpointLimit", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "AbsMinCoolSetpointLimit", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1600", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "AbsMaxCoolSetpointLimit", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3200", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "OccupiedCoolingSetpoint", + "code": 17, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0A28", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "OccupiedHeatingSetpoint", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x07D0", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MinHeatSetpointLimit", + "code": 21, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "700", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MaxHeatSetpointLimit", + "code": 22, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3000", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MinCoolSetpointLimit", + "code": 23, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1600", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "MaxCoolSetpointLimit", + "code": 24, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3200", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ControlSequenceOfOperation", + "code": 27, + "mfgCode": null, + "side": "server", + "type": "ControlSequenceOfOperationEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x04", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "SystemMode", + "code": 28, + "mfgCode": null, + "side": "server", + "type": "SystemModeEnum", + "included": 1, + "storageOption": "NVM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x01", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x3", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "7", + "reportable": 1, + "minInterval": 0, + "maxInterval": 65344, + "reportableChange": 0 + } + ] + } + ] + }, + { + "id": 3, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 145, + "profileId": 259, + "label": "MA-thread-border-router", + "name": "MA-thread-border-router" + }, + "deviceTypes": [ + { + "code": 145, + "profileId": 259, + "label": "MA-thread-border-router", + "name": "MA-thread-border-router" + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 145 + ], + "deviceTypeName": "MA-thread-border-router", + "deviceTypeCode": 145, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Thread Network Diagnostics", + "code": 53, + "mfgCode": null, + "define": "THREAD_NETWORK_DIAGNOSTICS_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "Channel", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RoutingRole", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "RoutingRoleEnum", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NetworkName", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PanId", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ExtendedPanId", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "MeshLocalPrefix", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "NeighborTable", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "RouteTable", + "code": 8, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartitionId", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "int32u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Weighting", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "DataVersion", + "code": 11, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "StableDataVersion", + "code": 12, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LeaderRouterId", + "code": 13, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SecurityPolicy", + "code": 59, + "mfgCode": null, + "side": "server", + "type": "SecurityPolicy", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ChannelPage0Mask", + "code": 60, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OperationalDatasetComponents", + "code": 61, + "mfgCode": null, + "side": "server", + "type": "OperationalDatasetComponents", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveNetworkFaultsList", + "code": 62, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Thread Border Router Management", + "code": 1106, + "mfgCode": null, + "define": "THREAD_BORDER_ROUTER_MANAGEMENT_CLUSTER", + "side": "server", + "enabled": 1, + "apiMaturity": "provisional", + "commands": [ + { + "name": "GetActiveDatasetRequest", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "GetPendingDatasetRequest", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "DatasetResponse", + "code": 2, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "SetActiveDatasetRequest", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "SetPendingDatasetRequest", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "BorderRouterName", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "char_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "BorderAgentID", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ThreadVersion", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "InterfaceEnabled", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ActiveDatasetTimestamp", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PendingDatasetTimestamp", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "int64u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + }, + { + "id": 4, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 25, + "profileId": 259, + "label": "MA-secondary-network-interface", + "name": "MA-secondary-network-interface" + }, + "deviceTypes": [ + { + "code": 25, + "profileId": 259, + "label": "MA-secondary-network-interface", + "name": "MA-secondary-network-interface" + } + ], + "deviceVersions": [ + 1 + ], + "deviceIdentifiers": [ + 25 + ], + "deviceTypeName": "MA-secondary-network-interface", + "deviceTypeCode": 25, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Network Commissioning", + "code": 49, + "mfgCode": null, + "define": "NETWORK_COMMISSIONING_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "ScanNetworks", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ScanNetworksResponse", + "code": 1, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "AddOrUpdateThreadNetwork", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "RemoveNetwork", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "NetworkConfigResponse", + "code": 5, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ConnectNetwork", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ConnectNetworkResponse", + "code": 7, + "mfgCode": null, + "source": "server", + "isIncoming": 0, + "isEnabled": 1 + }, + { + "name": "ReorderNetwork", + "code": 8, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "MaxNetworks", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "Networks", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ScanMaxTimeSeconds", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ConnectMaxTimeSeconds", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "int8u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "InterfaceEnabled", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "boolean", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkingStatus", + "code": 5, + "mfgCode": null, + "side": "server", + "type": "NetworkCommissioningStatusEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastNetworkID", + "code": 6, + "mfgCode": null, + "side": "server", + "type": "octet_string", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "LastConnectErrorValue", + "code": 7, + "mfgCode": null, + "side": "server", + "type": "int32s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SupportedThreadFeatures", + "code": 9, + "mfgCode": null, + "side": "server", + "type": "ThreadCapabilitiesBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ThreadVersion", + "code": 10, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": null, + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + } + ], + "endpoints": [ + { + "endpointTypeName": "MA-rootdevice", + "endpointTypeIndex": 0, + "profileId": 259, + "endpointId": 0, + "networkId": 0, + "parentEndpointIdentifier": null + }, + { + "endpointTypeName": "MA-thermostat", + "endpointTypeIndex": 1, + "profileId": 259, + "endpointId": 1, + "networkId": 0, + "parentEndpointIdentifier": null + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 2, + "profileId": 259, + "endpointId": 2, + "networkId": 0, + "parentEndpointIdentifier": null + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 3, + "profileId": 259, + "endpointId": 3, + "networkId": 0, + "parentEndpointIdentifier": null + } + ] +} \ No newline at end of file diff --git a/src/platform/nxp/common/ConnectivityManagerImpl.cpp b/src/platform/nxp/common/ConnectivityManagerImpl.cpp index 09d716ac6ea77f..3473fc7515e640 100644 --- a/src/platform/nxp/common/ConnectivityManagerImpl.cpp +++ b/src/platform/nxp/common/ConnectivityManagerImpl.cpp @@ -95,10 +95,6 @@ CHIP_ERROR ConnectivityManagerImpl::_Init() GenericConnectivityManagerImpl_Thread::_Init(); #endif -#if CHIP_DEVICE_CONFIG_ENABLE_WPA - StartWiFiManagement(); -#endif - SuccessOrExit(err); exit: @@ -614,6 +610,11 @@ CHIP_ERROR ConnectivityManagerImpl::ProvisionWiFiNetwork(const char * ssid, uint VerifyOrExit(ssidLen <= IEEEtypes_SSID_SIZE, ret = CHIP_ERROR_INVALID_ARGUMENT); VerifyOrExit(mWiFiStationState != kWiFiStationState_Connecting, ret = CHIP_ERROR_BUSY); + // Need to enable the WIFI interface here when Thread is enabled as a secondary network interface. We don't want to enable + // WIFI from the init phase anymore and we will only do it in case the commissioner is provisioning the device with + // the WIFI credentials. + StartWiFiManagement(); + memset(pNetworkData, 0, sizeof(struct wlan_network)); if (ssidLen < WLAN_NETWORK_NAME_MAX_LENGTH) diff --git a/src/platform/nxp/common/DnssdImpl.cpp b/src/platform/nxp/common/DnssdImpl.cpp index d0069cebcf1c4a..439327017897b2 100644 --- a/src/platform/nxp/common/DnssdImpl.cpp +++ b/src/platform/nxp/common/DnssdImpl.cpp @@ -1,6 +1,7 @@ /* * - * Copyright (c) 2023 Project CHIP Authors + * Copyright (c) 2024 Project CHIP Authors + * Copyright 2024 NXP * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,922 +17,118 @@ */ #include "lib/dnssd/platform/Dnssd.h" -#include -#include -#include -#include -#include +#include "platform/CHIPDeviceLayer.h" -#include +#include +#include +#include -#include -#include +#include +#include using namespace ::chip::DeviceLayer; -using namespace chip::DeviceLayer::Internal; namespace chip { namespace Dnssd { -#define USE_MDNS_NEXT_SERVICE_API 1 - -// Support both operational and commissionable discovery, so buffers sizes must be worst case. -static constexpr uint8_t kMaxMdnsServiceTxtEntriesNumber = - std::max(Dnssd::CommissionAdvertisingParameters::kTxtMaxNumber, Dnssd::OperationalAdvertisingParameters::kTxtMaxNumber); -static constexpr size_t kTotalMdnsServiceTxtValueSize = std::max(Dnssd::CommissionAdvertisingParameters::kTxtTotalValueSize, - Dnssd::OperationalAdvertisingParameters::kTxtTotalValueSize); -static constexpr size_t kTotalMdnsServiceTxtKeySize = - std::max(Dnssd::CommissionAdvertisingParameters::kTxtTotalKeySize, Dnssd::OperationalAdvertisingParameters::kTxtTotalKeySize); - -static constexpr size_t kTotalMdnsServiceTxtBufferSize = - kTotalMdnsServiceTxtKeySize + kMaxMdnsServiceTxtEntriesNumber + kTotalMdnsServiceTxtValueSize; - -// For each fabric we can register one _matter._tcp and one _matterc._udp service -static constexpr uint32_t kServiceListSize = CHIP_CONFIG_MAX_FABRICS * 2; - -static const char * GetProtocolString(DnssdServiceProtocol protocol) -{ - return protocol == DnssdServiceProtocol::kDnssdProtocolUdp ? "_udp" : "_tcp"; -} - -struct DnsServiceTxtEntries -{ - uint8_t mBuffer[kTotalMdnsServiceTxtBufferSize]; - Dnssd::TextEntry mTxtEntries[kMaxMdnsServiceTxtEntriesNumber]; -}; - -struct mDnsQueryCtx -{ - void * matterCtx; - chip::Dnssd::DnssdService mMdnsService; - DnsServiceTxtEntries mServiceTxtEntry; - char mServiceType[chip::Dnssd::kDnssdTypeAndProtocolMaxSize + 1]; - CHIP_ERROR error; - union - { - otMdnsBrowser mBrowseInfo; - otMdnsSrvResolver mSrvInfo; - otMdnsTxtResolver mTxtInfo; - otMdnsAddressResolver mAddrInfo; - }; - union - { - DnsBrowseCallback mDnsBrowseCallback; - DnsResolveCallback mDnsResolveCallback; - }; - - mDnsQueryCtx(void * context, DnsBrowseCallback aBrowseCallback) - { - matterCtx = context; - mDnsBrowseCallback = aBrowseCallback; - error = CHIP_NO_ERROR; - } - mDnsQueryCtx(void * context, DnsResolveCallback aResolveCallback) - { - matterCtx = context; - mDnsResolveCallback = aResolveCallback; - error = CHIP_NO_ERROR; - } -}; - -enum ResolveStep : uint8_t -{ - kResolveStepSrv = 0, - kResolveStepTxt, - kResolveStepIpAddr, -}; - -static const char * GetProtocolString(DnssdServiceProtocol protocol); - -static void OtBrowseCallback(otInstance * aInstance, const otMdnsBrowseResult * aResult); -static void OtServiceCallback(otInstance * aInstance, const otMdnsSrvResult * aResult); -static void OtTxtCallback(otInstance * aInstance, const otMdnsTxtResult * aResult); -static void OtAddressCallback(otInstance * aInstance, const otMdnsAddressResult * aResult); - -static void DispatchBrowseEmpty(intptr_t context); -static void DispatchBrowse(intptr_t context); - -static void DispatchTxtResolve(intptr_t context); -static void DispatchAddressResolve(intptr_t context); -static void DispatchResolve(intptr_t context); -static void DispatchResolveError(intptr_t context); - -static void HandleResolveCleanup(mDnsQueryCtx & resolveContext, ResolveStep stepType); - -static CHIP_ERROR ResolveBySrp(otInstance * thrInstancePtr, char * serviceName, mDnsQueryCtx * context, DnssdService * mdnsReq); -static CHIP_ERROR BrowseBySrp(otInstance * thrInstancePtr, char * serviceName, mDnsQueryCtx * context); -static CHIP_ERROR FromSrpCacheToMdnsData(const otSrpServerService * service, const otSrpServerHost * host, - const DnssdService * mdnsQueryReq, chip::Dnssd::DnssdService & mdnsService, - DnsServiceTxtEntries & serviceTxtEntries); - -static CHIP_ERROR FromServiceTypeToMdnsData(chip::Dnssd::DnssdService & mdnsService, const char * aServiceType); - -static bool bBrowseInProgress = false; -// ID 0 is reserved for host -static uint32_t mRegisterServiceId = 1; -static uint8_t mNetifIndex = 0; - -// Matter currently only supports one browse and resolve operation at a time so there is no need to create a list -// If the Matter implementation evolves in the future this functionality can be extended to a list. -static mDnsQueryCtx * mBrowseContext = nullptr; -static mDnsQueryCtx * mResolveContext = nullptr; - -#if USE_MDNS_NEXT_SERVICE_API -static otMdnsService * mServiceList[kServiceListSize]; -static uint32_t mServiceListFreeIndex; -#endif - CHIP_ERROR ChipDnssdInit(DnssdAsyncReturnCallback initCallback, DnssdAsyncReturnCallback errorCallback, void * context) { - CHIP_ERROR error = CHIP_NO_ERROR; - otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - struct netif * extNetif = (ConnectivityManagerImpl().GetExternalInterface()).GetPlatformInterface(); + NxpChipDnssdInit(initCallback, errorCallback, context); + OpenThreadDnssdInit(initCallback, errorCallback, context); - // Don't try to do anything until the mDNS server is started - VerifyOrExit(otMdnsIsEnabled(thrInstancePtr), error = CHIP_ERROR_INCORRECT_STATE); - - mNetifIndex = netif_get_index(extNetif); - -exit: - initCallback(context, error); - return error; + return CHIP_NO_ERROR; } void ChipDnssdShutdown() { - otMdnsSetEnabled(ThreadStackMgrImpl().OTInstance(), false, 0); + NxpChipDnssdShutdown(); } -#if USE_MDNS_NEXT_SERVICE_API -CHIP_ERROR ChipDnssdRemoveServices() -{ - otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - otMdnsService otServiceData = { 0 }; - otMdnsIterator * iterator = nullptr; - ChipError error = CHIP_NO_ERROR; - otError otError = OT_ERROR_NONE; - otMdnsEntryState state; - - const char * hostName = ConnectivityManagerImpl().GetHostName(); - - iterator = otMdnsAllocateIterator(thrInstancePtr); - VerifyOrExit(iterator != nullptr, error = CHIP_ERROR_NO_MEMORY); - - mServiceListFreeIndex = 0; - - while (mServiceListFreeIndex <= kServiceListSize) - { - // allocate memory for new entry if the entry is not allready allocated from previous iteration - if (mServiceList[mServiceListFreeIndex] == nullptr) - { - mServiceList[mServiceListFreeIndex] = static_cast(Platform::MemoryAlloc(sizeof(otMdnsService))); - VerifyOrExit(mServiceList[mServiceListFreeIndex] != nullptr, error = CHIP_ERROR_NO_MEMORY); - } - - otError = otMdnsGetNextService(thrInstancePtr, iterator, mServiceList[mServiceListFreeIndex], &state); - if (otError == OT_ERROR_NOT_FOUND) - { - Platform::MemoryFree(mServiceList[mServiceListFreeIndex]); - mServiceList[mServiceListFreeIndex] = nullptr; - break; - } - - if ((0 == strcmp(mServiceList[mServiceListFreeIndex]->mHostName, hostName)) && - ((0 == strcmp(mServiceList[mServiceListFreeIndex]->mServiceType, "_matter._tcp")) || - (0 == strcmp(mServiceList[mServiceListFreeIndex]->mServiceType, "_matterc._udp")))) - { - mServiceListFreeIndex++; - } - } - -exit: - if (iterator != nullptr) - { - otMdnsFreeIterator(thrInstancePtr, iterator); - } - return error; -} -#else -CHIP_ERROR ChipDnssdRemoveServices() -{ - otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - otMdnsService otServiceData = { 0 }; - - otServiceData.mHostName = ConnectivityManagerImpl().GetHostName(); - - otServiceData.mServiceType = "_matter._tcp"; - otMdnsUnregisterServiceType(thrInstancePtr, &otServiceData, OT_MDNS_SERVICE_MARK_FOR_UNREGISTER); - otServiceData.mServiceType = "_matterc._udp"; - otMdnsUnregisterServiceType(thrInstancePtr, &otServiceData, OT_MDNS_SERVICE_MARK_FOR_UNREGISTER); - - return CHIP_NO_ERROR; -} -#endif CHIP_ERROR ChipDnssdPublishService(const DnssdService * service, DnssdPublishCallback callback, void * context) { - ReturnErrorCodeIf(service == nullptr, CHIP_ERROR_INVALID_ARGUMENT); - - otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - uint32_t txtBufferOffset = 0; - otError otErr = OT_ERROR_NONE; - otMdnsService otServiceData = { 0 }; - -#if USE_MDNS_NEXT_SERVICE_API - bool bRegisterService = true; -#endif - - char serviceType[chip::Dnssd::kDnssdTypeAndProtocolMaxSize + 1] = ""; - snprintf(serviceType, sizeof(serviceType), "%s.%s", service->mType, GetProtocolString(service->mProtocol)); - - // secure space for the raw TXT data in the worst-case scenario relevant for Matter: - // each entry consists of txt_entry_size (1B) + txt_entry_key + "=" + txt_entry_data - uint8_t txtBuffer[kMaxMdnsServiceTxtEntriesNumber + kTotalMdnsServiceTxtBufferSize] = { 0 }; - - // Don't try to do anything until the mDNS server is started - VerifyOrReturnValue(otMdnsIsEnabled(thrInstancePtr), CHIP_NO_ERROR); - - // Create TXT Data as one string from multiple key entries - for (uint32_t i = 0; i < service->mTextEntrySize; i++) + if (ConnectivityMgr().IsWiFiStationConnected()) { - uint32_t keySize = strlen(service->mTextEntries[i].mKey); - // add TXT entry len, + 1 is for '=' - *(txtBuffer + txtBufferOffset++) = keySize + service->mTextEntries[i].mDataSize + 1; - - // add TXT entry key - memcpy(txtBuffer + txtBufferOffset, service->mTextEntries[i].mKey, keySize); - txtBufferOffset += keySize; - - // add TXT entry value if pointer is not null, if pointer is null it means we have bool value - if (service->mTextEntries[i].mData) - { - *(txtBuffer + txtBufferOffset++) = '='; - memcpy(txtBuffer + txtBufferOffset, service->mTextEntries[i].mData, service->mTextEntries[i].mDataSize); - txtBufferOffset += service->mTextEntries[i].mDataSize; - } - } - -#if USE_MDNS_NEXT_SERVICE_API - for (uint32_t i = 0; i < mServiceListFreeIndex; i++) - { - if ((0 == strcmp(mServiceList[i]->mHostName, service->mHostName)) && - (0 == strcmp(mServiceList[i]->mServiceInstance, service->mName)) && - (0 == strcmp(mServiceList[i]->mServiceType, serviceType))) - { - if ((mServiceList[i]->mTxtDataLength == txtBufferOffset) && - (0 == memcmp(txtBuffer, mServiceList[i]->mTxtData, txtBufferOffset))) - { - // In this case the service is - bRegisterService = false; - } - Platform::MemoryFree(mServiceList[i]); - if (i < --mServiceListFreeIndex) - { - // move last element in place of the removed one - mServiceList[i] = mServiceList[mServiceListFreeIndex]; - mServiceList[mServiceListFreeIndex] = nullptr; - } - else - { - mServiceList[i] = nullptr; - } - break; - } - } -#endif - if (bRegisterService) - { - if (strcmp(service->mHostName, "") != 0) - { - otServiceData.mHostName = service->mHostName; - } - - otServiceData.mServiceInstance = service->mName; - otServiceData.mServiceType = serviceType; - otServiceData.mSubTypeLabels = service->mSubTypes; - otServiceData.mSubTypeLabelsLength = service->mSubTypeSize; - otServiceData.mPort = service->mPort; - otServiceData.mTtl = service->mTtlSeconds; - otServiceData.mTxtData = txtBuffer; - otServiceData.mTxtDataLength = txtBufferOffset; - - otErr = otMdnsRegisterService(thrInstancePtr, &otServiceData, mRegisterServiceId++, NULL); + ReturnErrorOnFailure(NxpChipDnssdPublishService(service, callback, context)); } - - return MapOpenThreadError(otErr); -} - -#if USE_MDNS_NEXT_SERVICE_API -CHIP_ERROR ChipDnssdFinalizeServiceUpdate() -{ - otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - - for (uint32_t i = 0; i < mServiceListFreeIndex; i++) + else if (ConnectivityMgr().IsThreadProvisioned()) { - if (mServiceList[i] != nullptr) - { - otMdnsUnregisterService(thrInstancePtr, mServiceList[i]); - Platform::MemoryFree(mServiceList[i]); - mServiceList[i] = nullptr; - } + ReturnErrorOnFailure(OpenThreadDnssdPublishService(service, callback, context)); } - mServiceListFreeIndex = 0; return CHIP_NO_ERROR; } -#else -CHIP_ERROR ChipDnssdFinalizeServiceUpdate() -{ - otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - otMdnsService otServiceData = { 0 }; - - otServiceData.mHostName = ConnectivityManagerImpl().GetHostName(); - - otServiceData.mServiceType = "_matter._tcp"; - otMdnsUnregisterServiceType(thrInstancePtr, &otServiceData, OT_MDNS_SERVICE_UNREGISTER_MARKED_SERVICE); - otServiceData.mServiceType = "_matterc._udp"; - otMdnsUnregisterServiceType(thrInstancePtr, &otServiceData, OT_MDNS_SERVICE_UNREGISTER_MARKED_SERVICE); - - return CHIP_NO_ERROR; -} -#endif - -CHIP_ERROR ChipDnssdBrowse(const char * type, DnssdServiceProtocol protocol, Inet::IPAddressType addressType, - Inet::InterfaceId interface, DnssdBrowseCallback callback, void * context, intptr_t * browseIdentifier) -{ - *browseIdentifier = reinterpret_cast(nullptr); - CHIP_ERROR error = CHIP_NO_ERROR; - CHIP_ERROR srpBrowseError = CHIP_NO_ERROR; - otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - - if (type == nullptr || callback == nullptr) - return CHIP_ERROR_INVALID_ARGUMENT; - - mBrowseContext = Platform::New(context, callback); - VerifyOrReturnError(mBrowseContext != nullptr, CHIP_ERROR_NO_MEMORY); - - // First try to browse the service in the SRP cache - snprintf(mBrowseContext->mServiceType, sizeof(mBrowseContext->mServiceType), "%s.%s", type, GetProtocolString(protocol)); - // After browsing in the SRP cache we will continue with regular mDNS browse - srpBrowseError = BrowseBySrp(thrInstancePtr, mBrowseContext->mServiceType, mBrowseContext); - - // Proceed to generate a mDNS query - mBrowseContext->mBrowseInfo.mServiceType = mBrowseContext->mServiceType; - mBrowseContext->mBrowseInfo.mSubTypeLabel = nullptr; - mBrowseContext->mBrowseInfo.mInfraIfIndex = mNetifIndex; - mBrowseContext->mBrowseInfo.mCallback = OtBrowseCallback; - - error = MapOpenThreadError(otMdnsStartBrowser(thrInstancePtr, &mBrowseContext->mBrowseInfo)); - - if (CHIP_NO_ERROR == error) - { - bBrowseInProgress = true; - *browseIdentifier = reinterpret_cast(mBrowseContext); - } - else - { - if (srpBrowseError == CHIP_NO_ERROR) - { - // In this case, we need to send a final browse indication to signal the Matter App that there are no more - // browse results coming - mBrowseContext->error = error; - DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowseEmpty, reinterpret_cast(mBrowseContext)); - } - else - { - Platform::Delete(mBrowseContext); - mBrowseContext = nullptr; - } - } - return error; -} - -CHIP_ERROR ChipDnssdStopBrowse(intptr_t browseIdentifier) -{ - mDnsQueryCtx * browseContext = reinterpret_cast(browseIdentifier); - otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - otError error = OT_ERROR_INVALID_ARGS; - - // browseContext is only valid when bBrowseInProgress is true. The Matter stack can call this function even with a browseContext - // that has been freed in DispatchBrowseEmpty. - if ((true == bBrowseInProgress) && (browseContext)) - { - browseContext->error = MapOpenThreadError(otMdnsStopBrowser(thrInstancePtr, &browseContext->mBrowseInfo)); - - // browse context will be freed in DispatchBrowseEmpty - DispatchBrowseEmpty(reinterpret_cast(browseContext)); - } - return MapOpenThreadError(error); -} - -CHIP_ERROR ChipDnssdResolve(DnssdService * browseResult, Inet::InterfaceId interface, DnssdResolveCallback callback, void * context) -{ - ChipError error = CHIP_ERROR_NOT_FOUND; - - if (browseResult == nullptr || callback == nullptr) - return CHIP_ERROR_INVALID_ARGUMENT; - - otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); - - mResolveContext = Platform::New(context, callback); - VerifyOrReturnError(mResolveContext != nullptr, CHIP_ERROR_NO_MEMORY); - - // First try to find the service in the SRP cache, use default.service.arpa as domain name - snprintf(mResolveContext->mServiceType, sizeof(mResolveContext->mServiceType), "%s.%s", browseResult->mType, - GetProtocolString(browseResult->mProtocol)); - - error = ResolveBySrp(thrInstancePtr, mResolveContext->mServiceType, mResolveContext, browseResult); - // If the SRP cache returns not found, proceed to generate a MDNS query - if (CHIP_ERROR_NOT_FOUND == error) - { - // The otMdnsSrvResolver structure contains only pointers to instance name and service type strings - // Use the memory from mMdnsService.mName to store the instance name string we are looking for - Platform::CopyString(mResolveContext->mMdnsService.mName, sizeof(mResolveContext->mMdnsService.mName), browseResult->mName); - - mResolveContext->mSrvInfo.mInfraIfIndex = mNetifIndex; - mResolveContext->mSrvInfo.mCallback = OtServiceCallback; - mResolveContext->mSrvInfo.mServiceInstance = mResolveContext->mMdnsService.mName; - mResolveContext->mSrvInfo.mServiceType = mResolveContext->mServiceType; - - return MapOpenThreadError(otMdnsStartSrvResolver(thrInstancePtr, &mResolveContext->mSrvInfo)); - } - else - { - return error; - } -} -void ChipDnssdResolveNoLongerNeeded(const char * instanceName) -{ - if (mResolveContext != nullptr) - { - if (strcmp(instanceName, mResolveContext->mMdnsService.mName) == 0) - { - otMdnsStopSrvResolver(ThreadStackMgrImpl().OTInstance(), &mResolveContext->mSrvInfo); - - Platform::Delete(mResolveContext); - mResolveContext = nullptr; - } - } -} - -CHIP_ERROR ChipDnssdReconfirmRecord(const char * hostname, chip::Inet::IPAddress address, chip::Inet::InterfaceId interface) -{ - return CHIP_ERROR_NOT_IMPLEMENTED; -} - -CHIP_ERROR BrowseBySrp(otInstance * thrInstancePtr, char * serviceName, mDnsQueryCtx * context) -{ - const otSrpServerHost * host = nullptr; - const otSrpServerService * service = nullptr; - CHIP_ERROR error = CHIP_ERROR_NOT_FOUND; - - while ((host = otSrpServerGetNextHost(thrInstancePtr, host)) != nullptr) - { - while ((service = otSrpServerHostGetNextService(host, service)) != nullptr) - { - if ((false == otSrpServerServiceIsDeleted(service)) && - (0 == strncmp(otSrpServerServiceGetServiceName(service), serviceName, strlen(serviceName)))) - { - mDnsQueryCtx * serviceContext = Platform::New(context->matterCtx, context->mDnsBrowseCallback); - if (serviceContext != nullptr) - { - if (CHIP_NO_ERROR == - FromSrpCacheToMdnsData(service, host, nullptr, serviceContext->mMdnsService, - serviceContext->mServiceTxtEntry)) - { - // Set error to CHIP_NO_ERROR to signal that there was at least one service found in the cache - error = CHIP_NO_ERROR; - DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowse, reinterpret_cast(serviceContext)); - } - else - { - Platform::Delete(serviceContext); - } - } - } - } - } - return error; -} - -CHIP_ERROR ResolveBySrp(otInstance * thrInstancePtr, char * serviceName, mDnsQueryCtx * context, DnssdService * mdnsReq) -{ - const otSrpServerHost * host = nullptr; - const otSrpServerService * service = nullptr; - CHIP_ERROR error = CHIP_ERROR_NOT_FOUND; - - while ((host = otSrpServerGetNextHost(thrInstancePtr, host)) != nullptr) - { - while ((service = otSrpServerHostGetNextService(host, service)) != nullptr) - { - if ((false == otSrpServerServiceIsDeleted(service)) && - (0 == strncmp(otSrpServerServiceGetServiceName(service), serviceName, strlen(serviceName))) && - (0 == strncmp(otSrpServerServiceGetInstanceName(service), mdnsReq->mName, strlen(mdnsReq->mName)))) - { - error = FromSrpCacheToMdnsData(service, host, mdnsReq, context->mMdnsService, context->mServiceTxtEntry); - if (error == CHIP_NO_ERROR) - { - DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolve, reinterpret_cast(context)); - } - break; - } - } - - if (error == CHIP_NO_ERROR) - { - break; - } - } - - return error; -} - -CHIP_ERROR FromSrpCacheToMdnsData(const otSrpServerService * service, const otSrpServerHost * host, - const DnssdService * mdnsQueryReq, chip::Dnssd::DnssdService & mdnsService, - DnsServiceTxtEntries & serviceTxtEntries) +CHIP_ERROR ChipDnssdRemoveServices() { - const char * tmpName; - const uint8_t * txtStringPtr; - size_t substringSize; - uint8_t addrNum = 0; - uint16_t txtDataLen; - const otIp6Address * ip6AddrPtr = otSrpServerHostGetAddresses(host, &addrNum); - - if (mdnsQueryReq != nullptr) - { - Platform::CopyString(mdnsService.mName, sizeof(mdnsService.mName), mdnsQueryReq->mName); - Platform::CopyString(mdnsService.mType, sizeof(mdnsService.mType), mdnsQueryReq->mType); - mdnsService.mProtocol = mdnsQueryReq->mProtocol; - } - else + if (ConnectivityMgr().IsWiFiStationConnected()) { - tmpName = otSrpServerServiceGetInstanceName(service); - // Extract from the .... the part - size_t substringSize = strchr(tmpName, '.') - tmpName; - if (substringSize >= ArraySize(mdnsService.mName)) - { - return CHIP_ERROR_INVALID_ARGUMENT; - } - Platform::CopyString(mdnsService.mName, substringSize + 1, tmpName); - - // Extract from the .... the part. - tmpName = tmpName + substringSize + 1; - substringSize = strchr(tmpName, '.') - tmpName; - if (substringSize >= ArraySize(mdnsService.mType)) - { - return CHIP_ERROR_INVALID_ARGUMENT; - } - Platform::CopyString(mdnsService.mType, substringSize + 1, tmpName); - - // Extract from the .... the part. - tmpName = tmpName + substringSize + 1; - substringSize = strchr(tmpName, '.') - tmpName; - if (substringSize >= (chip::Dnssd::kDnssdProtocolTextMaxSize + 1)) - { - return CHIP_ERROR_INVALID_ARGUMENT; - } - if (strncmp(tmpName, "_udp", substringSize) == 0) - { - mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolUdp; - } - else if (strncmp(tmpName, "_tcp", substringSize) == 0) - { - mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolTcp; - } - else - { - mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolUnknown; - } + ReturnErrorOnFailure(NxpChipDnssdRemoveServices()); } - - // Extract from the .. the part. - tmpName = otSrpServerHostGetFullName(host); - substringSize = strchr(tmpName, '.') - tmpName; - if (substringSize >= ArraySize(mdnsService.mHostName)) + else if (ConnectivityMgr().IsThreadProvisioned()) { - return CHIP_ERROR_INVALID_ARGUMENT; + ReturnErrorOnFailure(OpenThreadDnssdRemoveServices()); } - Platform::CopyString(mdnsService.mHostName, substringSize + 1, tmpName); - mdnsService.mPort = otSrpServerServiceGetPort(service); - - // All SRP cache hits come from the Thread Netif - mdnsService.mInterface = ConnectivityManagerImpl().GetThreadInterface(); - - mdnsService.mAddressType = Inet::IPAddressType::kIPv6; - mdnsService.mAddress = std::optional(ToIPAddress(*ip6AddrPtr)); - - // Extract TXT record SRP service - txtStringPtr = otSrpServerServiceGetTxtData(service, &txtDataLen); - if (txtDataLen != 0) - { - otDnsTxtEntryIterator iterator; - otDnsInitTxtEntryIterator(&iterator, txtStringPtr, txtDataLen); - - otDnsTxtEntry txtEntry; - chip::FixedBufferAllocator alloc(serviceTxtEntries.mBuffer); - - uint8_t entryIndex = 0; - while ((otDnsGetNextTxtEntry(&iterator, &txtEntry) == OT_ERROR_NONE) && entryIndex < 64) - { - if (txtEntry.mKey == nullptr || txtEntry.mValue == nullptr) - continue; - - serviceTxtEntries.mTxtEntries[entryIndex].mKey = alloc.Clone(txtEntry.mKey); - serviceTxtEntries.mTxtEntries[entryIndex].mData = alloc.Clone(txtEntry.mValue, txtEntry.mValueLength); - serviceTxtEntries.mTxtEntries[entryIndex].mDataSize = txtEntry.mValueLength; - entryIndex++; - } - - ReturnErrorCodeIf(alloc.AnyAllocFailed(), CHIP_ERROR_BUFFER_TOO_SMALL); - - mdnsService.mTextEntries = serviceTxtEntries.mTxtEntries; - mdnsService.mTextEntrySize = entryIndex; - } - else - { - mdnsService.mTextEntrySize = 0; - } - - mdnsService.mSubTypes = nullptr; - mdnsService.mSubTypeSize = 0; return CHIP_NO_ERROR; } -static CHIP_ERROR FromServiceTypeToMdnsData(chip::Dnssd::DnssdService & mdnsService, const char * aServiceType) +CHIP_ERROR ChipDnssdFinalizeServiceUpdate() { - char protocol[chip::Dnssd::kDnssdProtocolTextMaxSize + 1]; - const char * protocolSubstringStart; - size_t substringSize; - - // Extract from the . the part. - substringSize = strchr(aServiceType, '.') - aServiceType; - if (substringSize >= ArraySize(mdnsService.mType)) - { - return CHIP_ERROR_INVALID_ARGUMENT; - } - Platform::CopyString(mdnsService.mType, ArraySize(mdnsService.mType), aServiceType); - - // Extract from the .. the . part. - protocolSubstringStart = aServiceType + substringSize; - - // Check that the protocolSubstringStart starts wit a '.' to be sure we are in the right place - if (strchr(protocolSubstringStart, '.') == nullptr) + if (ConnectivityMgr().IsWiFiStationConnected()) { - return CHIP_ERROR_INVALID_ARGUMENT; + ReturnErrorOnFailure(NxpChipDnssdFinalizeServiceUpdate()); } - - // Jump over '.' in protocolSubstringStart and substract the string terminator from the size - substringSize = strlen(++protocolSubstringStart) - 1; - if (substringSize >= ArraySize(protocol)) + else if (ConnectivityMgr().IsThreadProvisioned()) { - return CHIP_ERROR_INVALID_ARGUMENT; + ReturnErrorOnFailure(OpenThreadDnssdFinalizeServiceUpdate()); } - Platform::CopyString(protocol, ArraySize(protocol), protocolSubstringStart); - - if (strncmp(protocol, "_udp", chip::Dnssd::kDnssdProtocolTextMaxSize) == 0) - { - mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolUdp; - } - else if (strncmp(protocol, "_tcp", chip::Dnssd::kDnssdProtocolTextMaxSize) == 0) - { - mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolTcp; - } - else - { - mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolUnknown; - } - return CHIP_NO_ERROR; } -static void OtBrowseCallback(otInstance * aInstance, const otMdnsBrowseResult * aResult) +CHIP_ERROR ChipDnssdBrowse(const char * type, DnssdServiceProtocol protocol, chip::Inet::IPAddressType addressType, + chip::Inet::InterfaceId interface, DnssdBrowseCallback callback, void * context, + intptr_t * browseIdentifier) { - CHIP_ERROR error; - - // Ingnore reponses with TTL 0, the record is no longer valid and was removed from the mDNS cache - VerifyOrReturn(aResult->mTtl > 0); - - mDnsQueryCtx * tmpContext = Platform::New(mBrowseContext->matterCtx, mBrowseContext->mDnsBrowseCallback); - VerifyOrReturn(tmpContext != nullptr); - - Platform::CopyString(tmpContext->mMdnsService.mName, sizeof(tmpContext->mMdnsService.mName), aResult->mServiceInstance); - error = FromServiceTypeToMdnsData(tmpContext->mMdnsService, aResult->mServiceType); - - if (CHIP_NO_ERROR == error) + if (ConnectivityMgr().IsWiFiStationConnected()) //|| ESP32Utils::HasIPv6LinkLocalAddress(ESP32Utils::kDefaultEthernetNetifKey)) { - DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowse, reinterpret_cast(tmpContext)); + ReturnErrorOnFailure(NxpChipDnssdBrowse(type, protocol, addressType, interface, callback, context, browseIdentifier)); } - else + else if (ConnectivityMgr().IsThreadProvisioned()) { - Platform::Delete(tmpContext); + ReturnErrorOnFailure(OpenThreadDnssdBrowse(type, protocol, addressType, interface, callback, context, browseIdentifier)); } -} - -static void OtServiceCallback(otInstance * aInstance, const otMdnsSrvResult * aResult) -{ - CHIP_ERROR error; - - // Ingnore reponses with TTL 0, the record is no longer valid and was removed from the mDNS cache - VerifyOrReturn(aResult->mTtl > 0); - VerifyOrReturn(mResolveContext != nullptr); - - error = FromServiceTypeToMdnsData(mResolveContext->mMdnsService, aResult->mServiceType); - mResolveContext->error = error; - - if (CHIP_NO_ERROR == error) - { - Platform::CopyString(mResolveContext->mMdnsService.mName, sizeof(mResolveContext->mMdnsService.mName), - aResult->mServiceInstance); - Platform::CopyString(mResolveContext->mMdnsService.mHostName, sizeof(mResolveContext->mMdnsService.mHostName), - aResult->mHostName); - - mResolveContext->mMdnsService.mPort = aResult->mPort; - mResolveContext->mMdnsService.mTtlSeconds = aResult->mTtl; - DeviceLayer::PlatformMgr().ScheduleWork(DispatchTxtResolve, reinterpret_cast(mResolveContext)); - } - else - { - HandleResolveCleanup(*mResolveContext, kResolveStepSrv); - } -} - -static void OtTxtCallback(otInstance * aInstance, const otMdnsTxtResult * aResult) -{ - bool bSendDispatch = true; - - // Ingnore reponses with TTL 0, the record is no longer valid and was removed from the mDNS cache - VerifyOrReturn(aResult->mTtl > 0); - - VerifyOrReturn(mResolveContext != nullptr); - - // Check if TXT record was included in the response. - if (aResult->mTxtDataLength != 0) - { - otDnsTxtEntryIterator iterator; - otDnsInitTxtEntryIterator(&iterator, aResult->mTxtData, aResult->mTxtDataLength); - - otDnsTxtEntry txtEntry; - chip::FixedBufferAllocator alloc(mResolveContext->mServiceTxtEntry.mBuffer); - - uint8_t entryIndex = 0; - while ((otDnsGetNextTxtEntry(&iterator, &txtEntry) == OT_ERROR_NONE) && entryIndex < 64) - { - if (txtEntry.mKey == nullptr || txtEntry.mValue == nullptr) - continue; - - mResolveContext->mServiceTxtEntry.mTxtEntries[entryIndex].mKey = alloc.Clone(txtEntry.mKey); - mResolveContext->mServiceTxtEntry.mTxtEntries[entryIndex].mData = alloc.Clone(txtEntry.mValue, txtEntry.mValueLength); - mResolveContext->mServiceTxtEntry.mTxtEntries[entryIndex].mDataSize = txtEntry.mValueLength; - entryIndex++; - } - - if (alloc.AnyAllocFailed()) - { - bSendDispatch = false; - } - else - { - mResolveContext->mMdnsService.mTextEntries = mResolveContext->mServiceTxtEntry.mTxtEntries; - mResolveContext->mMdnsService.mTextEntrySize = entryIndex; - } - } - else - { - mResolveContext->mMdnsService.mTextEntrySize = 0; - } - - if (bSendDispatch) - { - DeviceLayer::PlatformMgr().ScheduleWork(DispatchAddressResolve, reinterpret_cast(mResolveContext)); - } - else - { - HandleResolveCleanup(*mResolveContext, kResolveStepTxt); - } -} - -static void OtAddressCallback(otInstance * aInstance, const otMdnsAddressResult * aResult) -{ - // Ingnore reponses with TTL 0, the record is no longer valid and was removed from the mDNS cache - VerifyOrReturn((aResult->mAddressesLength > 0) && (aResult->mAddresses[0].mTtl > 0)); - - VerifyOrReturn(mResolveContext != nullptr); - - mResolveContext->mMdnsService.mAddressType = Inet::IPAddressType::kIPv6; - mResolveContext->mMdnsService.mAddress = std::optional(ToIPAddress(aResult->mAddresses[0].mAddress)); - - DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolve, reinterpret_cast(mResolveContext)); -} - -static void DispatchBrowseEmpty(intptr_t context) -{ - auto * browseContext = reinterpret_cast(context); - browseContext->mDnsBrowseCallback(browseContext->matterCtx, nullptr, 0, true, browseContext->error); - Platform::Delete(browseContext); - mBrowseContext = nullptr; - bBrowseInProgress = false; + return CHIP_NO_ERROR; } -static void DispatchBrowse(intptr_t context) +CHIP_ERROR ChipDnssdStopBrowse(intptr_t browseIdentifier) { - auto * browseContext = reinterpret_cast(context); - browseContext->mDnsBrowseCallback(browseContext->matterCtx, &browseContext->mMdnsService, 1, false, browseContext->error); - Platform::Delete(browseContext); + return NxpChipDnssdStopBrowse(browseIdentifier); } -static void DispatchTxtResolve(intptr_t context) +CHIP_ERROR ChipDnssdResolve(DnssdService * service, chip::Inet::InterfaceId interface, DnssdResolveCallback callback, + void * context) { - mDnsQueryCtx * resolveContext = reinterpret_cast(context); - otError error; - - // Stop SRV resolver before starting TXT one, ignore error as it will only happen if mMDS module is not initialized - otMdnsStopSrvResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mSrvInfo); - - resolveContext->mTxtInfo.mServiceInstance = resolveContext->mMdnsService.mName; - resolveContext->mTxtInfo.mServiceType = resolveContext->mServiceType; - resolveContext->mTxtInfo.mCallback = OtTxtCallback; - resolveContext->mTxtInfo.mInfraIfIndex = mNetifIndex; - - error = otMdnsStartTxtResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mTxtInfo); - if (error != OT_ERROR_NONE) + if (ConnectivityMgr().IsWiFiStationConnected()) //|| ESP32Utils::HasIPv6LinkLocalAddress(ESP32Utils::kDefaultEthernetNetifKey)) { - resolveContext->error = MapOpenThreadError(error); - DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolveError, reinterpret_cast(resolveContext)); + ReturnErrorOnFailure(NxpChipDnssdResolve(service, interface, callback, context)); } -} - -static void DispatchAddressResolve(intptr_t context) -{ - otError error; - mDnsQueryCtx * resolveContext = reinterpret_cast(context); - // Stop TXT resolver before starting address one, ignore error as it will only happen if mMDS module is not initialized - otMdnsStopTxtResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mTxtInfo); - - resolveContext->mAddrInfo.mCallback = OtAddressCallback; - resolveContext->mAddrInfo.mHostName = resolveContext->mMdnsService.mHostName; - resolveContext->mAddrInfo.mInfraIfIndex = mNetifIndex; - - error = otMdnsStartIp6AddressResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mAddrInfo); - if (error != OT_ERROR_NONE) + else if (ConnectivityMgr().IsThreadProvisioned()) { - resolveContext->error = MapOpenThreadError(error); - DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolveError, reinterpret_cast(resolveContext)); + ReturnErrorOnFailure(OpenThreadDnssdResolve(service, interface, callback, context)); } -} -static void DispatchResolve(intptr_t context) -{ - mDnsQueryCtx * resolveContext = reinterpret_cast(context); - Dnssd::DnssdService & service = resolveContext->mMdnsService; - Span ipAddrs; - - // Stop Address resolver, we have finished resolving the service - otMdnsStopIp6AddressResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mAddrInfo); - - if (service.mAddress.has_value()) - { - ipAddrs = Span(&*service.mAddress, 1); - } - - // Signal that the context will be freed and that the resolve operation is stopped because Matter will - // try do stop it again on the mDnsResolveCallback - mResolveContext = nullptr; - - resolveContext->mDnsResolveCallback(resolveContext->matterCtx, &service, ipAddrs, resolveContext->error); - Platform::Delete(resolveContext); + return CHIP_NO_ERROR; } -static void DispatchResolveError(intptr_t context) +void ChipDnssdResolveNoLongerNeeded(const char * instanceName) { - mDnsQueryCtx * resolveContext = reinterpret_cast(context); - Span ipAddrs; - - // Signal that the context will be freed and that the resolve operation is stopped because Matter will - // try do stop it again on the mDnsResolveCallback - mResolveContext = nullptr; - - resolveContext->mDnsResolveCallback(resolveContext->matterCtx, nullptr, ipAddrs, resolveContext->error); - Platform::Delete(resolveContext); + NxpChipDnssdResolveNoLongerNeeded(instanceName); } -void HandleResolveCleanup(mDnsQueryCtx & resolveContext, ResolveStep stepType) +CHIP_ERROR ChipDnssdReconfirmRecord(const char * hostname, chip::Inet::IPAddress address, chip::Inet::InterfaceId interface) { - switch (stepType) - { - case kResolveStepSrv: - otMdnsStopSrvResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext.mSrvInfo); - break; - case kResolveStepTxt: - otMdnsStopTxtResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext.mTxtInfo); - break; - case kResolveStepIpAddr: - otMdnsStopIp6AddressResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext.mAddrInfo); - break; - } - - DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolve, reinterpret_cast(&resolveContext)); + return CHIP_ERROR_NOT_IMPLEMENTED; } } // namespace Dnssd diff --git a/src/platform/nxp/common/DnssdImplBr.cpp b/src/platform/nxp/common/DnssdImplBr.cpp new file mode 100644 index 00000000000000..6b84f1f258d8be --- /dev/null +++ b/src/platform/nxp/common/DnssdImplBr.cpp @@ -0,0 +1,939 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * Copyright 2024 NXP + * + * 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 "lib/dnssd/platform/Dnssd.h" +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace ::chip::DeviceLayer; +using namespace chip::DeviceLayer::Internal; + +namespace chip { +namespace Dnssd { + +#define USE_MDNS_NEXT_SERVICE_API 1 + +// Support both operational and commissionable discovery, so buffers sizes must be worst case. +static constexpr uint8_t kMaxMdnsServiceTxtEntriesNumber = + std::max(Dnssd::CommissionAdvertisingParameters::kTxtMaxNumber, Dnssd::OperationalAdvertisingParameters::kTxtMaxNumber); +static constexpr size_t kTotalMdnsServiceTxtValueSize = std::max(Dnssd::CommissionAdvertisingParameters::kTxtTotalValueSize, + Dnssd::OperationalAdvertisingParameters::kTxtTotalValueSize); +static constexpr size_t kTotalMdnsServiceTxtKeySize = + std::max(Dnssd::CommissionAdvertisingParameters::kTxtTotalKeySize, Dnssd::OperationalAdvertisingParameters::kTxtTotalKeySize); + +static constexpr size_t kTotalMdnsServiceTxtBufferSize = + kTotalMdnsServiceTxtKeySize + kMaxMdnsServiceTxtEntriesNumber + kTotalMdnsServiceTxtValueSize; + +// For each fabric we can register one _matter._tcp and one _matterc._udp service +static constexpr uint32_t kServiceListSize = CHIP_CONFIG_MAX_FABRICS * 2; + +static const char * GetProtocolString(DnssdServiceProtocol protocol) +{ + return protocol == DnssdServiceProtocol::kDnssdProtocolUdp ? "_udp" : "_tcp"; +} + +struct DnsServiceTxtEntries +{ + uint8_t mBuffer[kTotalMdnsServiceTxtBufferSize]; + Dnssd::TextEntry mTxtEntries[kMaxMdnsServiceTxtEntriesNumber]; +}; + +struct mDnsQueryCtx +{ + void * matterCtx; + chip::Dnssd::DnssdService mMdnsService; + DnsServiceTxtEntries mServiceTxtEntry; + char mServiceType[chip::Dnssd::kDnssdTypeAndProtocolMaxSize + 1]; + CHIP_ERROR error; + union + { + otMdnsBrowser mBrowseInfo; + otMdnsSrvResolver mSrvInfo; + otMdnsTxtResolver mTxtInfo; + otMdnsAddressResolver mAddrInfo; + }; + union + { + DnsBrowseCallback mDnsBrowseCallback; + DnsResolveCallback mDnsResolveCallback; + }; + + mDnsQueryCtx(void * context, DnsBrowseCallback aBrowseCallback) + { + matterCtx = context; + mDnsBrowseCallback = aBrowseCallback; + error = CHIP_NO_ERROR; + } + mDnsQueryCtx(void * context, DnsResolveCallback aResolveCallback) + { + matterCtx = context; + mDnsResolveCallback = aResolveCallback; + error = CHIP_NO_ERROR; + } +}; + +enum ResolveStep : uint8_t +{ + kResolveStepSrv = 0, + kResolveStepTxt, + kResolveStepIpAddr, +}; + +static const char * GetProtocolString(DnssdServiceProtocol protocol); + +static void OtBrowseCallback(otInstance * aInstance, const otMdnsBrowseResult * aResult); +static void OtServiceCallback(otInstance * aInstance, const otMdnsSrvResult * aResult); +static void OtTxtCallback(otInstance * aInstance, const otMdnsTxtResult * aResult); +static void OtAddressCallback(otInstance * aInstance, const otMdnsAddressResult * aResult); + +static void DispatchBrowseEmpty(intptr_t context); +static void DispatchBrowse(intptr_t context); + +static void DispatchTxtResolve(intptr_t context); +static void DispatchAddressResolve(intptr_t context); +static void DispatchResolve(intptr_t context); +static void DispatchResolveError(intptr_t context); + +static void HandleResolveCleanup(mDnsQueryCtx & resolveContext, ResolveStep stepType); + +static CHIP_ERROR ResolveBySrp(otInstance * thrInstancePtr, char * serviceName, mDnsQueryCtx * context, DnssdService * mdnsReq); +static CHIP_ERROR BrowseBySrp(otInstance * thrInstancePtr, char * serviceName, mDnsQueryCtx * context); +static CHIP_ERROR FromSrpCacheToMdnsData(const otSrpServerService * service, const otSrpServerHost * host, + const DnssdService * mdnsQueryReq, chip::Dnssd::DnssdService & mdnsService, + DnsServiceTxtEntries & serviceTxtEntries); + +static CHIP_ERROR FromServiceTypeToMdnsData(chip::Dnssd::DnssdService & mdnsService, const char * aServiceType); + +static bool bBrowseInProgress = false; +// ID 0 is reserved for host +static uint32_t mRegisterServiceId = 1; +static uint8_t mNetifIndex = 0; + +// Matter currently only supports one browse and resolve operation at a time so there is no need to create a list +// If the Matter implementation evolves in the future this functionality can be extended to a list. +static mDnsQueryCtx * mBrowseContext = nullptr; +static mDnsQueryCtx * mResolveContext = nullptr; + +#if USE_MDNS_NEXT_SERVICE_API +static otMdnsService * mServiceList[kServiceListSize]; +static uint32_t mServiceListFreeIndex; +#endif + +CHIP_ERROR NxpChipDnssdInit(DnssdAsyncReturnCallback initCallback, DnssdAsyncReturnCallback errorCallback, void * context) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + struct netif * extNetif = (ConnectivityManagerImpl().GetExternalInterface()).GetPlatformInterface(); + + // Don't try to do anything until the mDNS server is started + VerifyOrExit(otMdnsIsEnabled(thrInstancePtr), error = CHIP_ERROR_INCORRECT_STATE); + + mNetifIndex = netif_get_index(extNetif); + +exit: + initCallback(context, error); + return error; +} + +void NxpChipDnssdShutdown() +{ + otMdnsSetEnabled(ThreadStackMgrImpl().OTInstance(), false, 0); +} +#if USE_MDNS_NEXT_SERVICE_API +CHIP_ERROR NxpChipDnssdRemoveServices() +{ + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + otMdnsService otServiceData = { 0 }; + otMdnsIterator * iterator = nullptr; + ChipError error = CHIP_NO_ERROR; + otError otError = OT_ERROR_NONE; + otMdnsEntryState state; + + const char * hostName = ConnectivityManagerImpl().GetHostName(); + + iterator = otMdnsAllocateIterator(thrInstancePtr); + VerifyOrExit(iterator != nullptr, error = CHIP_ERROR_NO_MEMORY); + + mServiceListFreeIndex = 0; + + while (mServiceListFreeIndex <= kServiceListSize) + { + // allocate memory for new entry if the entry is not allready allocated from previous iteration + if (mServiceList[mServiceListFreeIndex] == nullptr) + { + mServiceList[mServiceListFreeIndex] = static_cast(Platform::MemoryAlloc(sizeof(otMdnsService))); + VerifyOrExit(mServiceList[mServiceListFreeIndex] != nullptr, error = CHIP_ERROR_NO_MEMORY); + } + + otError = otMdnsGetNextService(thrInstancePtr, iterator, mServiceList[mServiceListFreeIndex], &state); + if (otError == OT_ERROR_NOT_FOUND) + { + Platform::MemoryFree(mServiceList[mServiceListFreeIndex]); + mServiceList[mServiceListFreeIndex] = nullptr; + break; + } + + if ((0 == strcmp(mServiceList[mServiceListFreeIndex]->mHostName, hostName)) && + ((0 == strcmp(mServiceList[mServiceListFreeIndex]->mServiceType, "_matter._tcp")) || + (0 == strcmp(mServiceList[mServiceListFreeIndex]->mServiceType, "_matterc._udp")))) + { + mServiceListFreeIndex++; + } + } + +exit: + if (iterator != nullptr) + { + otMdnsFreeIterator(thrInstancePtr, iterator); + } + return error; +} +#else +CHIP_ERROR NxpChipDnssdRemoveServices() +{ + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + otMdnsService otServiceData = { 0 }; + + otServiceData.mHostName = ConnectivityManagerImpl().GetHostName(); + + otServiceData.mServiceType = "_matter._tcp"; + otMdnsUnregisterServiceType(thrInstancePtr, &otServiceData, OT_MDNS_SERVICE_MARK_FOR_UNREGISTER); + otServiceData.mServiceType = "_matterc._udp"; + otMdnsUnregisterServiceType(thrInstancePtr, &otServiceData, OT_MDNS_SERVICE_MARK_FOR_UNREGISTER); + + return CHIP_NO_ERROR; +} +#endif + +CHIP_ERROR NxpChipDnssdPublishService(const DnssdService * service, DnssdPublishCallback callback, void * context) +{ + ReturnErrorCodeIf(service == nullptr, CHIP_ERROR_INVALID_ARGUMENT); + + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + uint32_t txtBufferOffset = 0; + otError otErr = OT_ERROR_NONE; + otMdnsService otServiceData = { 0 }; + +#if USE_MDNS_NEXT_SERVICE_API + bool bRegisterService = true; +#endif + + char serviceType[chip::Dnssd::kDnssdTypeAndProtocolMaxSize + 1] = ""; + snprintf(serviceType, sizeof(serviceType), "%s.%s", service->mType, GetProtocolString(service->mProtocol)); + + // secure space for the raw TXT data in the worst-case scenario relevant for Matter: + // each entry consists of txt_entry_size (1B) + txt_entry_key + "=" + txt_entry_data + uint8_t txtBuffer[kMaxMdnsServiceTxtEntriesNumber + kTotalMdnsServiceTxtBufferSize] = { 0 }; + + // Don't try to do anything until the mDNS server is started + VerifyOrReturnValue(otMdnsIsEnabled(thrInstancePtr), CHIP_NO_ERROR); + + // Create TXT Data as one string from multiple key entries + for (uint32_t i = 0; i < service->mTextEntrySize; i++) + { + uint32_t keySize = strlen(service->mTextEntries[i].mKey); + // add TXT entry len, + 1 is for '=' + *(txtBuffer + txtBufferOffset++) = keySize + service->mTextEntries[i].mDataSize + 1; + + // add TXT entry key + memcpy(txtBuffer + txtBufferOffset, service->mTextEntries[i].mKey, keySize); + txtBufferOffset += keySize; + + // add TXT entry value if pointer is not null, if pointer is null it means we have bool value + if (service->mTextEntries[i].mData) + { + *(txtBuffer + txtBufferOffset++) = '='; + memcpy(txtBuffer + txtBufferOffset, service->mTextEntries[i].mData, service->mTextEntries[i].mDataSize); + txtBufferOffset += service->mTextEntries[i].mDataSize; + } + } + +#if USE_MDNS_NEXT_SERVICE_API + for (uint32_t i = 0; i < mServiceListFreeIndex; i++) + { + if ((0 == strcmp(mServiceList[i]->mHostName, service->mHostName)) && + (0 == strcmp(mServiceList[i]->mServiceInstance, service->mName)) && + (0 == strcmp(mServiceList[i]->mServiceType, serviceType))) + { + if ((mServiceList[i]->mTxtDataLength == txtBufferOffset) && + (0 == memcmp(txtBuffer, mServiceList[i]->mTxtData, txtBufferOffset))) + { + // In this case the service is + bRegisterService = false; + } + Platform::MemoryFree(mServiceList[i]); + if (i < --mServiceListFreeIndex) + { + // move last element in place of the removed one + mServiceList[i] = mServiceList[mServiceListFreeIndex]; + mServiceList[mServiceListFreeIndex] = nullptr; + } + else + { + mServiceList[i] = nullptr; + } + break; + } + } +#endif + if (bRegisterService) + { + if (strcmp(service->mHostName, "") != 0) + { + otServiceData.mHostName = service->mHostName; + } + + otServiceData.mServiceInstance = service->mName; + otServiceData.mServiceType = serviceType; + otServiceData.mSubTypeLabels = service->mSubTypes; + otServiceData.mSubTypeLabelsLength = service->mSubTypeSize; + otServiceData.mPort = service->mPort; + otServiceData.mTtl = service->mTtlSeconds; + otServiceData.mTxtData = txtBuffer; + otServiceData.mTxtDataLength = txtBufferOffset; + + otErr = otMdnsRegisterService(thrInstancePtr, &otServiceData, mRegisterServiceId++, NULL); + } + + return MapOpenThreadError(otErr); +} + +#if USE_MDNS_NEXT_SERVICE_API +CHIP_ERROR NxpChipDnssdFinalizeServiceUpdate() +{ + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + + for (uint32_t i = 0; i < mServiceListFreeIndex; i++) + { + if (mServiceList[i] != nullptr) + { + otMdnsUnregisterService(thrInstancePtr, mServiceList[i]); + Platform::MemoryFree(mServiceList[i]); + mServiceList[i] = nullptr; + } + } + + mServiceListFreeIndex = 0; + return CHIP_NO_ERROR; +} + +#else +CHIP_ERROR NxpChipDnssdFinalizeServiceUpdate() +{ + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + otMdnsService otServiceData = { 0 }; + + otServiceData.mHostName = ConnectivityManagerImpl().GetHostName(); + + otServiceData.mServiceType = "_matter._tcp"; + otMdnsUnregisterServiceType(thrInstancePtr, &otServiceData, OT_MDNS_SERVICE_UNREGISTER_MARKED_SERVICE); + otServiceData.mServiceType = "_matterc._udp"; + otMdnsUnregisterServiceType(thrInstancePtr, &otServiceData, OT_MDNS_SERVICE_UNREGISTER_MARKED_SERVICE); + + return CHIP_NO_ERROR; +} +#endif + +CHIP_ERROR NxpChipDnssdBrowse(const char * type, DnssdServiceProtocol protocol, Inet::IPAddressType addressType, + Inet::InterfaceId interface, DnssdBrowseCallback callback, void * context, + intptr_t * browseIdentifier) +{ + *browseIdentifier = reinterpret_cast(nullptr); + CHIP_ERROR error = CHIP_NO_ERROR; + CHIP_ERROR srpBrowseError = CHIP_NO_ERROR; + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + + if (type == nullptr || callback == nullptr) + return CHIP_ERROR_INVALID_ARGUMENT; + + mBrowseContext = Platform::New(context, callback); + VerifyOrReturnError(mBrowseContext != nullptr, CHIP_ERROR_NO_MEMORY); + + // First try to browse the service in the SRP cache + snprintf(mBrowseContext->mServiceType, sizeof(mBrowseContext->mServiceType), "%s.%s", type, GetProtocolString(protocol)); + // After browsing in the SRP cache we will continue with regular mDNS browse + srpBrowseError = BrowseBySrp(thrInstancePtr, mBrowseContext->mServiceType, mBrowseContext); + + // Proceed to generate a mDNS query + mBrowseContext->mBrowseInfo.mServiceType = mBrowseContext->mServiceType; + mBrowseContext->mBrowseInfo.mSubTypeLabel = nullptr; + mBrowseContext->mBrowseInfo.mInfraIfIndex = mNetifIndex; + mBrowseContext->mBrowseInfo.mCallback = OtBrowseCallback; + + error = MapOpenThreadError(otMdnsStartBrowser(thrInstancePtr, &mBrowseContext->mBrowseInfo)); + + if (CHIP_NO_ERROR == error) + { + bBrowseInProgress = true; + *browseIdentifier = reinterpret_cast(mBrowseContext); + } + else + { + if (srpBrowseError == CHIP_NO_ERROR) + { + // In this case, we need to send a final browse indication to signal the Matter App that there are no more + // browse results coming + mBrowseContext->error = error; + DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowseEmpty, reinterpret_cast(mBrowseContext)); + } + else + { + Platform::Delete(mBrowseContext); + mBrowseContext = nullptr; + } + } + return error; +} + +CHIP_ERROR NxpChipDnssdStopBrowse(intptr_t browseIdentifier) +{ + mDnsQueryCtx * browseContext = reinterpret_cast(browseIdentifier); + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + otError error = OT_ERROR_INVALID_ARGS; + + // browseContext is only valid when bBrowseInProgress is true. The Matter stack can call this function even with a browseContext + // that has been freed in DispatchBrowseEmpty. + if ((true == bBrowseInProgress) && (browseContext)) + { + browseContext->error = MapOpenThreadError(otMdnsStopBrowser(thrInstancePtr, &browseContext->mBrowseInfo)); + + // browse context will be freed in DispatchBrowseEmpty + DispatchBrowseEmpty(reinterpret_cast(browseContext)); + } + return MapOpenThreadError(error); +} + +CHIP_ERROR NxpChipDnssdResolve(DnssdService * browseResult, Inet::InterfaceId interface, DnssdResolveCallback callback, + void * context) +{ + ChipError error = CHIP_ERROR_NOT_FOUND; + + if (browseResult == nullptr || callback == nullptr) + return CHIP_ERROR_INVALID_ARGUMENT; + + otInstance * thrInstancePtr = ThreadStackMgrImpl().OTInstance(); + + mResolveContext = Platform::New(context, callback); + VerifyOrReturnError(mResolveContext != nullptr, CHIP_ERROR_NO_MEMORY); + + // First try to find the service in the SRP cache, use default.service.arpa as domain name + snprintf(mResolveContext->mServiceType, sizeof(mResolveContext->mServiceType), "%s.%s", browseResult->mType, + GetProtocolString(browseResult->mProtocol)); + + error = ResolveBySrp(thrInstancePtr, mResolveContext->mServiceType, mResolveContext, browseResult); + // If the SRP cache returns not found, proceed to generate a MDNS query + if (CHIP_ERROR_NOT_FOUND == error) + { + // The otMdnsSrvResolver structure contains only pointers to instance name and service type strings + // Use the memory from mMdnsService.mName to store the instance name string we are looking for + Platform::CopyString(mResolveContext->mMdnsService.mName, sizeof(mResolveContext->mMdnsService.mName), browseResult->mName); + + mResolveContext->mSrvInfo.mInfraIfIndex = mNetifIndex; + mResolveContext->mSrvInfo.mCallback = OtServiceCallback; + mResolveContext->mSrvInfo.mServiceInstance = mResolveContext->mMdnsService.mName; + mResolveContext->mSrvInfo.mServiceType = mResolveContext->mServiceType; + + return MapOpenThreadError(otMdnsStartSrvResolver(thrInstancePtr, &mResolveContext->mSrvInfo)); + } + else + { + return error; + } +} +void NxpChipDnssdResolveNoLongerNeeded(const char * instanceName) +{ + if (mResolveContext != nullptr) + { + if (strcmp(instanceName, mResolveContext->mMdnsService.mName) == 0) + { + otMdnsStopSrvResolver(ThreadStackMgrImpl().OTInstance(), &mResolveContext->mSrvInfo); + + Platform::Delete(mResolveContext); + mResolveContext = nullptr; + } + } +} + +CHIP_ERROR BrowseBySrp(otInstance * thrInstancePtr, char * serviceName, mDnsQueryCtx * context) +{ + const otSrpServerHost * host = nullptr; + const otSrpServerService * service = nullptr; + CHIP_ERROR error = CHIP_ERROR_NOT_FOUND; + + while ((host = otSrpServerGetNextHost(thrInstancePtr, host)) != nullptr) + { + while ((service = otSrpServerHostGetNextService(host, service)) != nullptr) + { + if ((false == otSrpServerServiceIsDeleted(service)) && + (0 == strncmp(otSrpServerServiceGetServiceName(service), serviceName, strlen(serviceName)))) + { + mDnsQueryCtx * serviceContext = Platform::New(context->matterCtx, context->mDnsBrowseCallback); + if (serviceContext != nullptr) + { + if (CHIP_NO_ERROR == + FromSrpCacheToMdnsData(service, host, nullptr, serviceContext->mMdnsService, + serviceContext->mServiceTxtEntry)) + { + // Set error to CHIP_NO_ERROR to signal that there was at least one service found in the cache + error = CHIP_NO_ERROR; + DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowse, reinterpret_cast(serviceContext)); + } + else + { + Platform::Delete(serviceContext); + } + } + } + } + } + return error; +} + +CHIP_ERROR ResolveBySrp(otInstance * thrInstancePtr, char * serviceName, mDnsQueryCtx * context, DnssdService * mdnsReq) +{ + const otSrpServerHost * host = nullptr; + const otSrpServerService * service = nullptr; + CHIP_ERROR error = CHIP_ERROR_NOT_FOUND; + + while ((host = otSrpServerGetNextHost(thrInstancePtr, host)) != nullptr) + { + while ((service = otSrpServerHostGetNextService(host, service)) != nullptr) + { + if ((false == otSrpServerServiceIsDeleted(service)) && + (0 == strncmp(otSrpServerServiceGetServiceName(service), serviceName, strlen(serviceName))) && + (0 == strncmp(otSrpServerServiceGetInstanceName(service), mdnsReq->mName, strlen(mdnsReq->mName)))) + { + error = FromSrpCacheToMdnsData(service, host, mdnsReq, context->mMdnsService, context->mServiceTxtEntry); + if (error == CHIP_NO_ERROR) + { + DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolve, reinterpret_cast(context)); + } + break; + } + } + + if (error == CHIP_NO_ERROR) + { + break; + } + } + + return error; +} + +CHIP_ERROR FromSrpCacheToMdnsData(const otSrpServerService * service, const otSrpServerHost * host, + const DnssdService * mdnsQueryReq, chip::Dnssd::DnssdService & mdnsService, + DnsServiceTxtEntries & serviceTxtEntries) +{ + const char * tmpName; + const uint8_t * txtStringPtr; + size_t substringSize; + uint8_t addrNum = 0; + uint16_t txtDataLen; + const otIp6Address * ip6AddrPtr = otSrpServerHostGetAddresses(host, &addrNum); + + if (mdnsQueryReq != nullptr) + { + Platform::CopyString(mdnsService.mName, sizeof(mdnsService.mName), mdnsQueryReq->mName); + Platform::CopyString(mdnsService.mType, sizeof(mdnsService.mType), mdnsQueryReq->mType); + mdnsService.mProtocol = mdnsQueryReq->mProtocol; + } + else + { + tmpName = otSrpServerServiceGetInstanceName(service); + // Extract from the .... the part + size_t substringSize = strchr(tmpName, '.') - tmpName; + if (substringSize >= ArraySize(mdnsService.mName)) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + Platform::CopyString(mdnsService.mName, substringSize + 1, tmpName); + + // Extract from the .... the part. + tmpName = tmpName + substringSize + 1; + substringSize = strchr(tmpName, '.') - tmpName; + if (substringSize >= ArraySize(mdnsService.mType)) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + Platform::CopyString(mdnsService.mType, substringSize + 1, tmpName); + + // Extract from the .... the part. + tmpName = tmpName + substringSize + 1; + substringSize = strchr(tmpName, '.') - tmpName; + if (substringSize >= (chip::Dnssd::kDnssdProtocolTextMaxSize + 1)) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + if (strncmp(tmpName, "_udp", substringSize) == 0) + { + mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolUdp; + } + else if (strncmp(tmpName, "_tcp", substringSize) == 0) + { + mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolTcp; + } + else + { + mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolUnknown; + } + } + + // Extract from the .. the part. + tmpName = otSrpServerHostGetFullName(host); + substringSize = strchr(tmpName, '.') - tmpName; + if (substringSize >= ArraySize(mdnsService.mHostName)) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + Platform::CopyString(mdnsService.mHostName, substringSize + 1, tmpName); + mdnsService.mPort = otSrpServerServiceGetPort(service); + + // All SRP cache hits come from the Thread Netif + mdnsService.mInterface = ConnectivityManagerImpl().GetThreadInterface(); + + mdnsService.mAddressType = Inet::IPAddressType::kIPv6; + mdnsService.mAddress = std::optional(ToIPAddress(*ip6AddrPtr)); + + // Extract TXT record SRP service + txtStringPtr = otSrpServerServiceGetTxtData(service, &txtDataLen); + if (txtDataLen != 0) + { + otDnsTxtEntryIterator iterator; + otDnsInitTxtEntryIterator(&iterator, txtStringPtr, txtDataLen); + + otDnsTxtEntry txtEntry; + chip::FixedBufferAllocator alloc(serviceTxtEntries.mBuffer); + + uint8_t entryIndex = 0; + while ((otDnsGetNextTxtEntry(&iterator, &txtEntry) == OT_ERROR_NONE) && entryIndex < 64) + { + if (txtEntry.mKey == nullptr || txtEntry.mValue == nullptr) + continue; + + serviceTxtEntries.mTxtEntries[entryIndex].mKey = alloc.Clone(txtEntry.mKey); + serviceTxtEntries.mTxtEntries[entryIndex].mData = alloc.Clone(txtEntry.mValue, txtEntry.mValueLength); + serviceTxtEntries.mTxtEntries[entryIndex].mDataSize = txtEntry.mValueLength; + entryIndex++; + } + + ReturnErrorCodeIf(alloc.AnyAllocFailed(), CHIP_ERROR_BUFFER_TOO_SMALL); + + mdnsService.mTextEntries = serviceTxtEntries.mTxtEntries; + mdnsService.mTextEntrySize = entryIndex; + } + else + { + mdnsService.mTextEntrySize = 0; + } + + mdnsService.mSubTypes = nullptr; + mdnsService.mSubTypeSize = 0; + + return CHIP_NO_ERROR; +} + +static CHIP_ERROR FromServiceTypeToMdnsData(chip::Dnssd::DnssdService & mdnsService, const char * aServiceType) +{ + char protocol[chip::Dnssd::kDnssdProtocolTextMaxSize + 1]; + const char * protocolSubstringStart; + size_t substringSize; + + // Extract from the . the part. + substringSize = strchr(aServiceType, '.') - aServiceType; + if (substringSize >= ArraySize(mdnsService.mType)) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + Platform::CopyString(mdnsService.mType, ArraySize(mdnsService.mType), aServiceType); + + // Extract from the .. the . part. + protocolSubstringStart = aServiceType + substringSize; + + // Check that the protocolSubstringStart starts wit a '.' to be sure we are in the right place + if (strchr(protocolSubstringStart, '.') == nullptr) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + // Jump over '.' in protocolSubstringStart and substract the string terminator from the size + substringSize = strlen(++protocolSubstringStart) - 1; + if (substringSize >= ArraySize(protocol)) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + Platform::CopyString(protocol, ArraySize(protocol), protocolSubstringStart); + + if (strncmp(protocol, "_udp", chip::Dnssd::kDnssdProtocolTextMaxSize) == 0) + { + mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolUdp; + } + else if (strncmp(protocol, "_tcp", chip::Dnssd::kDnssdProtocolTextMaxSize) == 0) + { + mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolTcp; + } + else + { + mdnsService.mProtocol = chip::Dnssd::DnssdServiceProtocol::kDnssdProtocolUnknown; + } + + // All mDNS replies come from the External Netif + mdnsService.mInterface = ConnectivityManagerImpl().GetExternalInterface(); + + return CHIP_NO_ERROR; +} + +static void OtBrowseCallback(otInstance * aInstance, const otMdnsBrowseResult * aResult) +{ + CHIP_ERROR error; + + // Ingnore reponses with TTL 0, the record is no longer valid and was removed from the mDNS cache + VerifyOrReturn(aResult->mTtl > 0); + + mDnsQueryCtx * tmpContext = Platform::New(mBrowseContext->matterCtx, mBrowseContext->mDnsBrowseCallback); + VerifyOrReturn(tmpContext != nullptr); + + Platform::CopyString(tmpContext->mMdnsService.mName, sizeof(tmpContext->mMdnsService.mName), aResult->mServiceInstance); + error = FromServiceTypeToMdnsData(tmpContext->mMdnsService, aResult->mServiceType); + + if (CHIP_NO_ERROR == error) + { + DeviceLayer::PlatformMgr().ScheduleWork(DispatchBrowse, reinterpret_cast(tmpContext)); + } + else + { + Platform::Delete(tmpContext); + } +} + +static void OtServiceCallback(otInstance * aInstance, const otMdnsSrvResult * aResult) +{ + CHIP_ERROR error; + + // Ingnore reponses with TTL 0, the record is no longer valid and was removed from the mDNS cache + VerifyOrReturn(aResult->mTtl > 0); + + VerifyOrReturn(mResolveContext != nullptr); + + error = FromServiceTypeToMdnsData(mResolveContext->mMdnsService, aResult->mServiceType); + mResolveContext->error = error; + + if (CHIP_NO_ERROR == error) + { + Platform::CopyString(mResolveContext->mMdnsService.mName, sizeof(mResolveContext->mMdnsService.mName), + aResult->mServiceInstance); + Platform::CopyString(mResolveContext->mMdnsService.mHostName, sizeof(mResolveContext->mMdnsService.mHostName), + aResult->mHostName); + + mResolveContext->mMdnsService.mPort = aResult->mPort; + mResolveContext->mMdnsService.mTtlSeconds = aResult->mTtl; + DeviceLayer::PlatformMgr().ScheduleWork(DispatchTxtResolve, reinterpret_cast(mResolveContext)); + } + else + { + HandleResolveCleanup(*mResolveContext, kResolveStepSrv); + } +} + +static void OtTxtCallback(otInstance * aInstance, const otMdnsTxtResult * aResult) +{ + bool bSendDispatch = true; + + // Ingnore reponses with TTL 0, the record is no longer valid and was removed from the mDNS cache + VerifyOrReturn(aResult->mTtl > 0); + + VerifyOrReturn(mResolveContext != nullptr); + + // Check if TXT record was included in the response. + if (aResult->mTxtDataLength != 0) + { + otDnsTxtEntryIterator iterator; + otDnsInitTxtEntryIterator(&iterator, aResult->mTxtData, aResult->mTxtDataLength); + + otDnsTxtEntry txtEntry; + chip::FixedBufferAllocator alloc(mResolveContext->mServiceTxtEntry.mBuffer); + + uint8_t entryIndex = 0; + while ((otDnsGetNextTxtEntry(&iterator, &txtEntry) == OT_ERROR_NONE) && entryIndex < 64) + { + if (txtEntry.mKey == nullptr || txtEntry.mValue == nullptr) + continue; + + mResolveContext->mServiceTxtEntry.mTxtEntries[entryIndex].mKey = alloc.Clone(txtEntry.mKey); + mResolveContext->mServiceTxtEntry.mTxtEntries[entryIndex].mData = alloc.Clone(txtEntry.mValue, txtEntry.mValueLength); + mResolveContext->mServiceTxtEntry.mTxtEntries[entryIndex].mDataSize = txtEntry.mValueLength; + entryIndex++; + } + + if (alloc.AnyAllocFailed()) + { + bSendDispatch = false; + } + else + { + mResolveContext->mMdnsService.mTextEntries = mResolveContext->mServiceTxtEntry.mTxtEntries; + mResolveContext->mMdnsService.mTextEntrySize = entryIndex; + } + } + else + { + mResolveContext->mMdnsService.mTextEntrySize = 0; + } + + if (bSendDispatch) + { + DeviceLayer::PlatformMgr().ScheduleWork(DispatchAddressResolve, reinterpret_cast(mResolveContext)); + } + else + { + HandleResolveCleanup(*mResolveContext, kResolveStepTxt); + } +} + +static void OtAddressCallback(otInstance * aInstance, const otMdnsAddressResult * aResult) +{ + // Ingnore reponses with TTL 0, the record is no longer valid and was removed from the mDNS cache + VerifyOrReturn((aResult->mAddressesLength > 0) && (aResult->mAddresses[0].mTtl > 0)); + + VerifyOrReturn(mResolveContext != nullptr); + + mResolveContext->mMdnsService.mAddressType = Inet::IPAddressType::kIPv6; + mResolveContext->mMdnsService.mAddress = std::optional(ToIPAddress(aResult->mAddresses[0].mAddress)); + + DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolve, reinterpret_cast(mResolveContext)); +} + +static void DispatchBrowseEmpty(intptr_t context) +{ + auto * browseContext = reinterpret_cast(context); + browseContext->mDnsBrowseCallback(browseContext->matterCtx, nullptr, 0, true, browseContext->error); + Platform::Delete(browseContext); + mBrowseContext = nullptr; + bBrowseInProgress = false; +} + +static void DispatchBrowse(intptr_t context) +{ + auto * browseContext = reinterpret_cast(context); + browseContext->mDnsBrowseCallback(browseContext->matterCtx, &browseContext->mMdnsService, 1, false, browseContext->error); + Platform::Delete(browseContext); +} + +static void DispatchTxtResolve(intptr_t context) +{ + mDnsQueryCtx * resolveContext = reinterpret_cast(context); + otError error; + + // Stop SRV resolver before starting TXT one, ignore error as it will only happen if mMDS module is not initialized + otMdnsStopSrvResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mSrvInfo); + + resolveContext->mTxtInfo.mServiceInstance = resolveContext->mMdnsService.mName; + resolveContext->mTxtInfo.mServiceType = resolveContext->mServiceType; + resolveContext->mTxtInfo.mCallback = OtTxtCallback; + resolveContext->mTxtInfo.mInfraIfIndex = mNetifIndex; + + error = otMdnsStartTxtResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mTxtInfo); + if (error != OT_ERROR_NONE) + { + resolveContext->error = MapOpenThreadError(error); + DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolveError, reinterpret_cast(resolveContext)); + } +} + +static void DispatchAddressResolve(intptr_t context) +{ + otError error; + mDnsQueryCtx * resolveContext = reinterpret_cast(context); + // Stop TXT resolver before starting address one, ignore error as it will only happen if mMDS module is not initialized + otMdnsStopTxtResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mTxtInfo); + + resolveContext->mAddrInfo.mCallback = OtAddressCallback; + resolveContext->mAddrInfo.mHostName = resolveContext->mMdnsService.mHostName; + resolveContext->mAddrInfo.mInfraIfIndex = mNetifIndex; + + error = otMdnsStartIp6AddressResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mAddrInfo); + if (error != OT_ERROR_NONE) + { + resolveContext->error = MapOpenThreadError(error); + DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolveError, reinterpret_cast(resolveContext)); + } +} + +static void DispatchResolve(intptr_t context) +{ + mDnsQueryCtx * resolveContext = reinterpret_cast(context); + Dnssd::DnssdService & service = resolveContext->mMdnsService; + Span ipAddrs; + + // Stop Address resolver, we have finished resolving the service + otMdnsStopIp6AddressResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext->mAddrInfo); + + if (service.mAddress.has_value()) + { + ipAddrs = Span(&*service.mAddress, 1); + } + + // Signal that the context will be freed and that the resolve operation is stopped because Matter will + // try do stop it again on the mDnsResolveCallback + mResolveContext = nullptr; + + resolveContext->mDnsResolveCallback(resolveContext->matterCtx, &service, ipAddrs, resolveContext->error); + Platform::Delete(resolveContext); +} + +static void DispatchResolveError(intptr_t context) +{ + mDnsQueryCtx * resolveContext = reinterpret_cast(context); + Span ipAddrs; + + // Signal that the context will be freed and that the resolve operation is stopped because Matter will + // try do stop it again on the mDnsResolveCallback + mResolveContext = nullptr; + + resolveContext->mDnsResolveCallback(resolveContext->matterCtx, nullptr, ipAddrs, resolveContext->error); + Platform::Delete(resolveContext); +} + +void HandleResolveCleanup(mDnsQueryCtx & resolveContext, ResolveStep stepType) +{ + switch (stepType) + { + case kResolveStepSrv: + otMdnsStopSrvResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext.mSrvInfo); + break; + case kResolveStepTxt: + otMdnsStopTxtResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext.mTxtInfo); + break; + case kResolveStepIpAddr: + otMdnsStopIp6AddressResolver(ThreadStackMgrImpl().OTInstance(), &resolveContext.mAddrInfo); + break; + } + + DeviceLayer::PlatformMgr().ScheduleWork(DispatchResolve, reinterpret_cast(&resolveContext)); +} + +} // namespace Dnssd +} // namespace chip diff --git a/src/platform/nxp/common/DnssdImplBr.h b/src/platform/nxp/common/DnssdImplBr.h new file mode 100644 index 00000000000000..970a2c675752b6 --- /dev/null +++ b/src/platform/nxp/common/DnssdImplBr.h @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * Copyright 2024 NXP + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace chip { +namespace Dnssd { + +CHIP_ERROR NxpChipDnssdInit(DnssdAsyncReturnCallback initCallback, DnssdAsyncReturnCallback errorCallback, void * context); + +void NxpChipDnssdShutdown(); + +CHIP_ERROR NxpChipDnssdPublishService(const DnssdService * service, DnssdPublishCallback callback, void * context); + +CHIP_ERROR NxpChipDnssdRemoveServices(); + +CHIP_ERROR NxpChipDnssdFinalizeServiceUpdate(); + +CHIP_ERROR NxpChipDnssdBrowse(const char * type, DnssdServiceProtocol protocol, chip::Inet::IPAddressType addressType, + chip::Inet::InterfaceId interface, DnssdBrowseCallback callback, void * context, + intptr_t * browseIdentifier); + +CHIP_ERROR NxpChipDnssdStopBrowse(intptr_t browseIdentifier); + +CHIP_ERROR NxpChipDnssdResolve(DnssdService * service, chip::Inet::InterfaceId interface, DnssdResolveCallback callback, + void * context); + +void NxpChipDnssdResolveNoLongerNeeded(const char * instanceName); + +} // namespace Dnssd +} // namespace chip diff --git a/src/platform/nxp/rt/rw61x/BUILD.gn b/src/platform/nxp/rt/rw61x/BUILD.gn index 447ef2905bb300..e80dd3cbd823f4 100644 --- a/src/platform/nxp/rt/rw61x/BUILD.gn +++ b/src/platform/nxp/rt/rw61x/BUILD.gn @@ -34,7 +34,10 @@ source_set("nxp_ota") { } config("nxp_platform_config") { - defines = [ "EXTERNAL_BLEMANAGERIMPL_HEADER=\"platform/nxp/common/ble_zephyr/BLEManagerImpl.h\"" ] + defines = [ + "EXTERNAL_BLEMANAGERIMPL_HEADER=\"platform/nxp/common/ble_zephyr/BLEManagerImpl.h\"", + "CONFIG_BOOT_REASON_SDK_SUPPORT=1", + ] include_dirs = [ ".", "../../common", @@ -63,8 +66,10 @@ config("nxp_platform_config") { defines += [ "EXTERNAL_FACTORY_DATA_PROVIDER_IMPL_HEADER=\"platform/nxp/common/factory_data/FactoryDataProviderFwkImpl.h\"" ] } } - if (chip_enable_wifi && chip_enable_openthread) { - # Disable thread nwk commissioning instance on endpoint 0, when OTBR is enabled + + # When OTBR is enabled Thread network commissioning cluster is enabled using chip_enable_secondary_nwk_if + if (chip_enable_wifi && chip_enable_openthread && + !chip_enable_secondary_nwk_if) { defines += [ "_NO_GENERIC_THREAD_NETWORK_COMMISSIONING_DRIVER_" ] } } @@ -154,17 +159,33 @@ static_library("nxp_platform") { if (chip_enable_openthread) { sources += [ + # Temporary fix, to be revert once PR #34662 is merged, build issue when using GN check argument + "${chip_root}/src/app/clusters/thread-border-router-management-server/thread-br-delegate.h", + "../../../OpenThread/GenericThreadBorderRouterDelegate.cpp", + "../../../OpenThread/GenericThreadBorderRouterDelegate.h", "../../../OpenThread/OpenThreadUtils.cpp", "../../common/ThreadStackManagerImpl.cpp", "../../common/ThreadStackManagerImpl.h", ] - deps += [ "${chip_root}/third_party/openthread:openthread" ] - public_deps += [ "${chip_root}/third_party/openthread:openthread-platform" ] + deps += [ "${chip_root}/src/app/common:ids" ] + + if (!nxp_build_matter_standalone_lib) { + deps += [ "${chip_root}/third_party/openthread:openthread" ] + public_deps += + [ "${chip_root}/third_party/openthread:openthread-platform" ] + } if (chip_mdns == "platform") { if (chip_enable_wifi) { - sources += [ "../../common/DnssdImpl.cpp" ] + sources += [ + "../../../OpenThread/DnssdImpl.cpp", + "../../../OpenThread/OpenThreadDnssdImpl.cpp", + "../../../OpenThread/OpenThreadDnssdImpl.h", + "../../common/DnssdImpl.cpp", + "../../common/DnssdImplBr.cpp", + "../../common/DnssdImplBr.h", + ] } else { sources += [ "../../../OpenThread/DnssdImpl.cpp", diff --git a/src/platform/nxp/rt/rw61x/PlatformManagerImpl.cpp b/src/platform/nxp/rt/rw61x/PlatformManagerImpl.cpp index c17e7df36c616c..fe8c6b012b4c3f 100644 --- a/src/platform/nxp/rt/rw61x/PlatformManagerImpl.cpp +++ b/src/platform/nxp/rt/rw61x/PlatformManagerImpl.cpp @@ -204,6 +204,7 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) otPlatLogInit(); otPlatRadioInit(); otPlatSetResetFunction(initiateResetInIdle); + otPlatRandomInit(); #endif #if CHIP_DEVICE_CONFIG_ENABLE_WPA diff --git a/src/platform/nxp/rt/rw61x/args.gni b/src/platform/nxp/rt/rw61x/args.gni index 5561196ea3a323..b9b34f2e7c3cbc 100644 --- a/src/platform/nxp/rt/rw61x/args.gni +++ b/src/platform/nxp/rt/rw61x/args.gni @@ -42,6 +42,8 @@ declare_args() { # if rw610_mbedtls_port_els_pkc is set to false software mbedtls is used instead rw610_mbedtls_port_els_pkc = true + + chip_enable_secondary_nwk_if = false } # TODO : Enable the OTA Requestor by default. diff --git a/third_party/openthread/ot-nxp b/third_party/openthread/ot-nxp index 0a3248f5c8ec5a..0a480829128901 160000 --- a/third_party/openthread/ot-nxp +++ b/third_party/openthread/ot-nxp @@ -1 +1 @@ -Subproject commit 0a3248f5c8ec5a9fd05541974872323f26d5182f +Subproject commit 0a4808291289019d0930a6a63afd87c2983353f5 diff --git a/third_party/openthread/platforms/nxp/rt/rw61x/BUILD.gn b/third_party/openthread/platforms/nxp/rt/rw61x/BUILD.gn index 6d4854f53a9160..86c9f2fe2d5c58 100644 --- a/third_party/openthread/platforms/nxp/rt/rw61x/BUILD.gn +++ b/third_party/openthread/platforms/nxp/rt/rw61x/BUILD.gn @@ -34,6 +34,9 @@ config("openthread_rw61x_config") { "${openthread_nxp_root}/third_party/mbedtls/configs", "${openthread_root}/third_party/mbedtls", "${openthread_root}/examples/platforms", + "${openthread_nxp_root}/examples/utils/cli_addons", + "${openthread_nxp_root}/examples/utils/cli_addons/ephemeral_key", + "${openthread_nxp_root}/examples/utils/cli_addons/lwip", ] if (spinel_interface_rpmsg) { include_dirs += [ "${openthread_nxp_root}/src/common/spinel" ] @@ -57,6 +60,14 @@ config("openthread_rw61x_config") { "OPENTHREAD_CONFIG_MULTICAST_DNS_PUBLIC_API_ENABLE=1", "OT_APP_BR_LWIP_HOOKS_EN=1", ] + + if (chip_enable_matter_cli) { + defines += [ + "OPENTHREAD_CONFIG_BORDER_AGENT_EPHEMERAL_KEY_ENABLE=1", + "OT_APP_CLI_EPHEMERAL_KEY_ADDON=1", + "OT_APP_CLI_LWIP_ADDON=1", + ] + } } # ot cli configs @@ -89,6 +100,15 @@ source_set("libopenthread-rw61x") { "${openthread_nxp_root}/src/common/br/udp_plat.c", "${openthread_nxp_root}/src/common/br/utils.c", ] + + if (chip_enable_matter_cli) { + sources += [ + "${openthread_nxp_root}/examples/utils/cli_addons/addons_cli.c", + "${openthread_nxp_root}/examples/utils/cli_addons/ephemeral_key/ephemeral_key_cli.c", + "${openthread_nxp_root}/examples/utils/cli_addons/lwip/lwip_cli.c", + ] + } + deps += [ "${nxp_sdk_build_root}:nxp_lwip" ] } if (spinel_interface_rpmsg) { From 756b329e9675f04bb1bb7f1ae2ea53ab09e21b00 Mon Sep 17 00:00:00 2001 From: Erwin Pan Date: Tue, 24 Sep 2024 21:41:35 +0800 Subject: [PATCH 14/19] Fix Chef AirQualitySensor temperature range (#35742) The original was setting maxMeasuredValue/maxMeasuredValue as 0x800 which doesn't make any senses. So it is modified to the reasonable values from -5000 (-50 celsius degrees) ~ 7000 (70 celsius degrees) --- .../devices/rootnode_airqualitysensor_e63187f6c9.matter | 6 +++--- .../chef/devices/rootnode_airqualitysensor_e63187f6c9.zap | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter b/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter index ee845c7c6cffda..ca3d431c3e81e8 100644 --- a/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter +++ b/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.matter @@ -2613,9 +2613,9 @@ endpoint 1 { } server cluster TemperatureMeasurement { - persist attribute measuredValue default = 0x800; - persist attribute minMeasuredValue default = 0x800; - persist attribute maxMeasuredValue default = 0x800; + persist attribute measuredValue default = 0; + persist attribute minMeasuredValue default = -5000; + persist attribute maxMeasuredValue default = 7500; persist attribute tolerance default = 0; callback attribute generatedCommandList; callback attribute acceptedCommandList; diff --git a/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.zap b/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.zap index 7e58d312609fc7..c5ad356e6d292a 100644 --- a/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.zap +++ b/examples/chef/devices/rootnode_airqualitysensor_e63187f6c9.zap @@ -3107,7 +3107,7 @@ "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "0x800", + "defaultValue": "0", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3123,7 +3123,7 @@ "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "0x800", + "defaultValue": "-5000", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -3139,7 +3139,7 @@ "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "0x800", + "defaultValue": "7500", "reportable": 1, "minInterval": 1, "maxInterval": 65534, From d3b645e42d659d512bce5a5904d7fb70de2fce4d Mon Sep 17 00:00:00 2001 From: Junior Martinez <67972863+jmartinez-silabs@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:10:42 -0400 Subject: [PATCH 15/19] conditional include of sl_matter_ota_config.h (#35724) --- examples/platform/silabs/OTAConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/platform/silabs/OTAConfig.h b/examples/platform/silabs/OTAConfig.h index c97202e401f266..07d61037a9b2ca 100644 --- a/examples/platform/silabs/OTAConfig.h +++ b/examples/platform/silabs/OTAConfig.h @@ -29,7 +29,7 @@ #include #endif -#if (SL_MATTER_GN_BUILD == 0) +#if (SL_MATTER_GN_BUILD == 0) && defined(SILABS_OTA_ENABLED) #include "sl_matter_ota_config.h" #endif From b6a130478931ddb006439e1d7baaba6ae1a7e106 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 24 Sep 2024 10:35:12 -0400 Subject: [PATCH 16/19] Add missing support for returning credential data in GetCredentialStatusResponse. (#35732) * Add missing support for returning credential data in GetCredentialStatusResponse. * Regenerate generated code. --- .../all-clusters-minimal-app.matter | 1 + .../rootnode_doorlock_aNKYAreMXE.matter | 1 + examples/lock-app/lock-common/lock-app.matter | 1 + examples/lock-app/nxp/zap/lock-app.matter | 1 + examples/lock-app/qpg/zap/lock.matter | 1 + .../placeholder/linux/apps/app1/config.matter | 2 ++ .../placeholder/linux/apps/app2/config.matter | 2 ++ .../virtual-device-app.matter | 1 + .../door-lock-server/door-lock-server.cpp | 23 ++++++++++++++++++ .../zcl/data-model/chip/door-lock-cluster.xml | 1 + .../data_model/controller-clusters.matter | 1 + .../chip/devicecontroller/ChipClusters.java | 11 +++++++-- .../devicecontroller/ClusterInfoMapping.java | 4 +++- .../cluster/clusters/DoorLockCluster.kt | 24 +++++++++++++++++++ .../python/chip/clusters/Objects.py | 2 ++ .../CHIP/templates/availability.yaml | 4 ++++ .../zap-generated/MTRCommandPayloadsObjc.h | 2 ++ .../zap-generated/MTRCommandPayloadsObjc.mm | 16 ++++++++++++- .../zap-generated/cluster-objects.cpp | 5 ++++ .../zap-generated/cluster-objects.h | 3 +++ .../cluster/logging/DataModelLogger.cpp | 1 + 21 files changed, 103 insertions(+), 4 deletions(-) diff --git a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter index 9b30603b156ee2..a261fb4070e0ed 100644 --- a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter +++ b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter @@ -3464,6 +3464,7 @@ cluster DoorLock = 257 { nullable fabric_idx creatorFabricIndex = 2; nullable fabric_idx lastModifiedFabricIndex = 3; nullable int16u nextCredentialIndex = 4; + optional nullable octet_string credentialData = 5; } request struct ClearCredentialRequest { diff --git a/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter b/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter index fc6ef7614fc562..36a7822ede2aa3 100644 --- a/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter +++ b/examples/chef/devices/rootnode_doorlock_aNKYAreMXE.matter @@ -2301,6 +2301,7 @@ cluster DoorLock = 257 { nullable fabric_idx creatorFabricIndex = 2; nullable fabric_idx lastModifiedFabricIndex = 3; nullable int16u nextCredentialIndex = 4; + optional nullable octet_string credentialData = 5; } request struct ClearCredentialRequest { diff --git a/examples/lock-app/lock-common/lock-app.matter b/examples/lock-app/lock-common/lock-app.matter index 0b316c77592d7e..45e530bbff9449 100644 --- a/examples/lock-app/lock-common/lock-app.matter +++ b/examples/lock-app/lock-common/lock-app.matter @@ -2728,6 +2728,7 @@ cluster DoorLock = 257 { nullable fabric_idx creatorFabricIndex = 2; nullable fabric_idx lastModifiedFabricIndex = 3; nullable int16u nextCredentialIndex = 4; + optional nullable octet_string credentialData = 5; } request struct ClearCredentialRequest { diff --git a/examples/lock-app/nxp/zap/lock-app.matter b/examples/lock-app/nxp/zap/lock-app.matter index 7c39ef0fe254eb..91e023d6607a6c 100644 --- a/examples/lock-app/nxp/zap/lock-app.matter +++ b/examples/lock-app/nxp/zap/lock-app.matter @@ -2304,6 +2304,7 @@ cluster DoorLock = 257 { nullable fabric_idx creatorFabricIndex = 2; nullable fabric_idx lastModifiedFabricIndex = 3; nullable int16u nextCredentialIndex = 4; + optional nullable octet_string credentialData = 5; } request struct ClearCredentialRequest { diff --git a/examples/lock-app/qpg/zap/lock.matter b/examples/lock-app/qpg/zap/lock.matter index 303b079b910cac..1d367e9eaeb42b 100644 --- a/examples/lock-app/qpg/zap/lock.matter +++ b/examples/lock-app/qpg/zap/lock.matter @@ -2401,6 +2401,7 @@ cluster DoorLock = 257 { nullable fabric_idx creatorFabricIndex = 2; nullable fabric_idx lastModifiedFabricIndex = 3; nullable int16u nextCredentialIndex = 4; + optional nullable octet_string credentialData = 5; } request struct ClearCredentialRequest { diff --git a/examples/placeholder/linux/apps/app1/config.matter b/examples/placeholder/linux/apps/app1/config.matter index de9603d2627962..6fcce30fe6b2a0 100644 --- a/examples/placeholder/linux/apps/app1/config.matter +++ b/examples/placeholder/linux/apps/app1/config.matter @@ -4098,6 +4098,7 @@ cluster DoorLock = 257 { nullable fabric_idx creatorFabricIndex = 2; nullable fabric_idx lastModifiedFabricIndex = 3; nullable int16u nextCredentialIndex = 4; + optional nullable octet_string credentialData = 5; } request struct ClearCredentialRequest { @@ -4749,6 +4750,7 @@ cluster DoorLock = 257 { nullable fabric_idx creatorFabricIndex = 2; nullable fabric_idx lastModifiedFabricIndex = 3; nullable int16u nextCredentialIndex = 4; + optional nullable octet_string credentialData = 5; } request struct ClearCredentialRequest { diff --git a/examples/placeholder/linux/apps/app2/config.matter b/examples/placeholder/linux/apps/app2/config.matter index 2b6528d55ad018..b2be5a5715779c 100644 --- a/examples/placeholder/linux/apps/app2/config.matter +++ b/examples/placeholder/linux/apps/app2/config.matter @@ -4055,6 +4055,7 @@ cluster DoorLock = 257 { nullable fabric_idx creatorFabricIndex = 2; nullable fabric_idx lastModifiedFabricIndex = 3; nullable int16u nextCredentialIndex = 4; + optional nullable octet_string credentialData = 5; } request struct ClearCredentialRequest { @@ -4706,6 +4707,7 @@ cluster DoorLock = 257 { nullable fabric_idx creatorFabricIndex = 2; nullable fabric_idx lastModifiedFabricIndex = 3; nullable int16u nextCredentialIndex = 4; + optional nullable octet_string credentialData = 5; } request struct ClearCredentialRequest { diff --git a/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter b/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter index 07baa25e19ebc3..eb7e56997ead55 100644 --- a/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter +++ b/examples/virtual-device-app/virtual-device-common/virtual-device-app.matter @@ -2939,6 +2939,7 @@ cluster DoorLock = 257 { nullable fabric_idx creatorFabricIndex = 2; nullable fabric_idx lastModifiedFabricIndex = 3; nullable int16u nextCredentialIndex = 4; + optional nullable octet_string credentialData = 5; } request struct ClearCredentialRequest { diff --git a/src/app/clusters/door-lock-server/door-lock-server.cpp b/src/app/clusters/door-lock-server/door-lock-server.cpp index 3842130aa356f1..43a044d0c4b9ec 100644 --- a/src/app/clusters/door-lock-server/door-lock-server.cpp +++ b/src/app/clusters/door-lock-server/door-lock-server.cpp @@ -900,6 +900,21 @@ void DoorLockServer::getCredentialStatusCommandHandler(chip::app::CommandHandler credentialExists); } +namespace { +bool IsAliroCredentialType(CredentialTypeEnum credentialType) +{ + switch (credentialType) + { + case CredentialTypeEnum::kAliroCredentialIssuerKey: + case CredentialTypeEnum::kAliroEvictableEndpointKey: + case CredentialTypeEnum::kAliroNonEvictableEndpointKey: + return true; + default: + return false; + } +} +} // anonymous namespace + void DoorLockServer::sendGetCredentialResponse(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, CredentialTypeEnum credentialType, uint16_t credentialIndex, @@ -921,10 +936,18 @@ void DoorLockServer::sendGetCredentialResponse(chip::app::CommandHandler * comma { response.lastModifiedFabricIndex.SetNonNull(credentialInfo->lastModifiedBy); } + if (IsAliroCredentialType(credentialType)) + { + response.credentialData.Emplace(credentialInfo->credentialData); + } } else { response.userIndex.SetNull(); + if (IsAliroCredentialType(credentialType)) + { + response.credentialData.Emplace(NullNullable); + } } uint16_t nextCredentialIndex = 0; if (findOccupiedCredentialSlot(commandPath.mEndpointId, credentialType, static_cast(credentialIndex + 1), diff --git a/src/app/zap-templates/zcl/data-model/chip/door-lock-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/door-lock-cluster.xml index 8ebb31df118d92..b25cd549d90091 100644 --- a/src/app/zap-templates/zcl/data-model/chip/door-lock-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/door-lock-cluster.xml @@ -491,6 +491,7 @@ limitations under the License. + diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 1ba56719ab4549..6c7748e0898737 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -6263,6 +6263,7 @@ cluster DoorLock = 257 { nullable fabric_idx creatorFabricIndex = 2; nullable fabric_idx lastModifiedFabricIndex = 3; nullable int16u nextCredentialIndex = 4; + optional nullable octet_string credentialData = 5; } request struct ClearCredentialRequest { diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index 2ce04c328ded6f..bb92218a4b4b59 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -35125,6 +35125,8 @@ public void onResponse(StructType invokeStructValue) { @Nullable Integer lastModifiedFabricIndex = null; final long nextCredentialIndexFieldID = 4L; @Nullable Integer nextCredentialIndex = null; + final long credentialDataFieldID = 5L; + @Nullable Optional credentialData = null; for (StructElement element: invokeStructValue.value()) { if (element.contextTagNum() == credentialExistsFieldID) { if (element.value(BaseTLVType.class).type() == TLVType.Boolean) { @@ -35151,9 +35153,14 @@ public void onResponse(StructType invokeStructValue) { UIntType castingValue = element.value(UIntType.class); nextCredentialIndex = castingValue.value(Integer.class); } + } else if (element.contextTagNum() == credentialDataFieldID) { + if (element.value(BaseTLVType.class).type() == TLVType.ByteArray) { + ByteArrayType castingValue = element.value(ByteArrayType.class); + credentialData = Optional.of(castingValue.value(byte[].class)); + } } } - callback.onSuccess(credentialExists, userIndex, creatorFabricIndex, lastModifiedFabricIndex, nextCredentialIndex); + callback.onSuccess(credentialExists, userIndex, creatorFabricIndex, lastModifiedFabricIndex, nextCredentialIndex, credentialData); }}, commandId, commandArgs, timedInvokeTimeoutMs); } @@ -35254,7 +35261,7 @@ public interface SetCredentialResponseCallback extends BaseClusterCallback { } public interface GetCredentialStatusResponseCallback extends BaseClusterCallback { - void onSuccess(Boolean credentialExists, @Nullable Integer userIndex, @Nullable Integer creatorFabricIndex, @Nullable Integer lastModifiedFabricIndex, @Nullable Integer nextCredentialIndex); + void onSuccess(Boolean credentialExists, @Nullable Integer userIndex, @Nullable Integer creatorFabricIndex, @Nullable Integer lastModifiedFabricIndex, @Nullable Integer nextCredentialIndex, @Nullable Optional credentialData); } public interface LockStateAttributeCallback extends BaseAttributeCallback { diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java index 40427e62794337..d10ce6b823d8d4 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterInfoMapping.java @@ -12382,7 +12382,7 @@ public void setCallbackDelegate(ClusterCommandCallback callback) { } @Override - public void onSuccess(Boolean credentialExists, @Nullable Integer userIndex, @Nullable Integer creatorFabricIndex, @Nullable Integer lastModifiedFabricIndex, @Nullable Integer nextCredentialIndex) { + public void onSuccess(Boolean credentialExists, @Nullable Integer userIndex, @Nullable Integer creatorFabricIndex, @Nullable Integer lastModifiedFabricIndex, @Nullable Integer nextCredentialIndex, @Nullable Optional credentialData) { Map responseValues = new LinkedHashMap<>(); CommandResponseInfo credentialExistsResponseValue = new CommandResponseInfo("credentialExists", "Boolean"); @@ -12395,6 +12395,8 @@ public void onSuccess(Boolean credentialExists, @Nullable Integer userIndex, @Nu responseValues.put(lastModifiedFabricIndexResponseValue, lastModifiedFabricIndex); CommandResponseInfo nextCredentialIndexResponseValue = new CommandResponseInfo("nextCredentialIndex", "Integer"); responseValues.put(nextCredentialIndexResponseValue, nextCredentialIndex); + CommandResponseInfo credentialDataResponseValue = new CommandResponseInfo("credentialData", "Optional"); + responseValues.put(credentialDataResponseValue, credentialData); callback.onSuccess(responseValues); } diff --git a/src/controller/java/generated/java/matter/controller/cluster/clusters/DoorLockCluster.kt b/src/controller/java/generated/java/matter/controller/cluster/clusters/DoorLockCluster.kt index ff0525a58d8c27..ad44768f35c71f 100644 --- a/src/controller/java/generated/java/matter/controller/cluster/clusters/DoorLockCluster.kt +++ b/src/controller/java/generated/java/matter/controller/cluster/clusters/DoorLockCluster.kt @@ -99,6 +99,7 @@ class DoorLockCluster(private val controller: MatterController, private val endp val creatorFabricIndex: UByte?, val lastModifiedFabricIndex: UByte?, val nextCredentialIndex: UShort?, + val credentialData: ByteArray?, ) class LockStateAttribute(val value: UByte?) @@ -1320,6 +1321,9 @@ class DoorLockCluster(private val controller: MatterController, private val endp val TAG_NEXT_CREDENTIAL_INDEX: Int = 4 var nextCredentialIndex_decoded: UShort? = null + val TAG_CREDENTIAL_DATA: Int = 5 + var credentialData_decoded: ByteArray? = null + while (!tlvReader.isEndOfContainer()) { val tag = tlvReader.peekElement().tag @@ -1385,6 +1389,25 @@ class DoorLockCluster(private val controller: MatterController, private val endp null } } + } + + if (tag == ContextSpecificTag(TAG_CREDENTIAL_DATA)) { + credentialData_decoded = + if (tlvReader.isNull()) { + tlvReader.getNull(tag) + null + } else { + if (!tlvReader.isNull()) { + if (tlvReader.isNextTag(tag)) { + tlvReader.getByteArray(tag) + } else { + null + } + } else { + tlvReader.getNull(tag) + null + } + } } else { tlvReader.skipElement() } @@ -1402,6 +1425,7 @@ class DoorLockCluster(private val controller: MatterController, private val endp creatorFabricIndex_decoded, lastModifiedFabricIndex_decoded, nextCredentialIndex_decoded, + credentialData_decoded, ) } diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index efefaf9059dd7f..6a9e0b8416fd5a 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -28861,6 +28861,7 @@ def descriptor(cls) -> ClusterObjectDescriptor: ClusterObjectFieldDescriptor(Label="creatorFabricIndex", Tag=2, Type=typing.Union[Nullable, uint]), ClusterObjectFieldDescriptor(Label="lastModifiedFabricIndex", Tag=3, Type=typing.Union[Nullable, uint]), ClusterObjectFieldDescriptor(Label="nextCredentialIndex", Tag=4, Type=typing.Union[Nullable, uint]), + ClusterObjectFieldDescriptor(Label="credentialData", Tag=5, Type=typing.Union[None, Nullable, bytes]), ]) credentialExists: 'bool' = False @@ -28868,6 +28869,7 @@ def descriptor(cls) -> ClusterObjectDescriptor: creatorFabricIndex: 'typing.Union[Nullable, uint]' = NullValue lastModifiedFabricIndex: 'typing.Union[Nullable, uint]' = NullValue nextCredentialIndex: 'typing.Union[Nullable, uint]' = NullValue + credentialData: 'typing.Union[None, Nullable, bytes]' = None @dataclass class ClearCredential(ClusterCommand): diff --git a/src/darwin/Framework/CHIP/templates/availability.yaml b/src/darwin/Framework/CHIP/templates/availability.yaml index 12458cdaec950d..3f65e9facfd3f1 100644 --- a/src/darwin/Framework/CHIP/templates/availability.yaml +++ b/src/darwin/Framework/CHIP/templates/availability.yaml @@ -9803,6 +9803,10 @@ - GlobalEchoResponse - StringEchoRequest - StringEchoResponse + command fields: + DoorLock: + GetCredentialStatusResponse: + - credentialData structs: AccessControl: # Targeting 1.4 diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h index 48e7175fa2c58b..7135f3d88d8357 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.h @@ -7212,6 +7212,8 @@ MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)) @property (nonatomic, copy) NSNumber * _Nullable lastModifiedFabricIndex MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); @property (nonatomic, copy) NSNumber * _Nullable nextCredentialIndex MTR_AVAILABLE(ios(16.1), macos(13.0), watchos(9.1), tvos(16.1)); + +@property (nonatomic, copy) NSData * _Nullable credentialData MTR_PROVISIONALLY_AVAILABLE; /** * Controls whether the command is a timed command (using Timed Invoke). * diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index ce78c58b074d32..ec90ce4d023543 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -20631,6 +20631,8 @@ - (instancetype)init _lastModifiedFabricIndex = nil; _nextCredentialIndex = nil; + + _credentialData = nil; _timedInvokeTimeoutMs = nil; } return self; @@ -20645,6 +20647,7 @@ - (id)copyWithZone:(NSZone * _Nullable)zone; other.creatorFabricIndex = self.creatorFabricIndex; other.lastModifiedFabricIndex = self.lastModifiedFabricIndex; other.nextCredentialIndex = self.nextCredentialIndex; + other.credentialData = self.credentialData; other.timedInvokeTimeoutMs = self.timedInvokeTimeoutMs; return other; @@ -20652,7 +20655,7 @@ - (id)copyWithZone:(NSZone * _Nullable)zone; - (NSString *)description { - NSString * descriptionString = [NSString stringWithFormat:@"<%@: credentialExists:%@; userIndex:%@; creatorFabricIndex:%@; lastModifiedFabricIndex:%@; nextCredentialIndex:%@; >", NSStringFromClass([self class]), _credentialExists, _userIndex, _creatorFabricIndex, _lastModifiedFabricIndex, _nextCredentialIndex]; + NSString * descriptionString = [NSString stringWithFormat:@"<%@: credentialExists:%@; userIndex:%@; creatorFabricIndex:%@; lastModifiedFabricIndex:%@; nextCredentialIndex:%@; credentialData:%@; >", NSStringFromClass([self class]), _credentialExists, _userIndex, _creatorFabricIndex, _lastModifiedFabricIndex, _nextCredentialIndex, [_credentialData base64EncodedStringWithOptions:0]]; return descriptionString; } @@ -20733,6 +20736,17 @@ - (CHIP_ERROR)_setFieldsFromDecodableStruct:(const chip::app::Clusters::DoorLock self.nextCredentialIndex = [NSNumber numberWithUnsignedShort:decodableStruct.nextCredentialIndex.Value()]; } } + { + if (decodableStruct.credentialData.HasValue()) { + if (decodableStruct.credentialData.Value().IsNull()) { + self.credentialData = nil; + } else { + self.credentialData = AsData(decodableStruct.credentialData.Value().Value()); + } + } else { + self.credentialData = nil; + } + } return CHIP_NO_ERROR; } diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp index 00e32012cb3be6..3029e317897ca2 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.cpp @@ -19400,6 +19400,7 @@ CHIP_ERROR Type::Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const encoder.Encode(to_underlying(Fields::kCreatorFabricIndex), creatorFabricIndex); encoder.Encode(to_underlying(Fields::kLastModifiedFabricIndex), lastModifiedFabricIndex); encoder.Encode(to_underlying(Fields::kNextCredentialIndex), nextCredentialIndex); + encoder.Encode(to_underlying(Fields::kCredentialData), credentialData); return encoder.Finalize(); } @@ -19437,6 +19438,10 @@ CHIP_ERROR DecodableType::Decode(TLV::TLVReader & reader) { err = DataModel::Decode(reader, nextCredentialIndex); } + else if (__context_tag == to_underlying(Fields::kCredentialData)) + { + err = DataModel::Decode(reader, credentialData); + } else { } diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h index f8847a3f1a0b51..16042f9eeb562f 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-objects.h @@ -26208,6 +26208,7 @@ enum class Fields : uint8_t kCreatorFabricIndex = 2, kLastModifiedFabricIndex = 3, kNextCredentialIndex = 4, + kCredentialData = 5, }; struct Type @@ -26222,6 +26223,7 @@ struct Type DataModel::Nullable creatorFabricIndex; DataModel::Nullable lastModifiedFabricIndex; DataModel::Nullable nextCredentialIndex; + Optional> credentialData; CHIP_ERROR Encode(TLV::TLVWriter & aWriter, TLV::Tag aTag) const; @@ -26241,6 +26243,7 @@ struct DecodableType DataModel::Nullable creatorFabricIndex; DataModel::Nullable lastModifiedFabricIndex; DataModel::Nullable nextCredentialIndex; + Optional> credentialData; CHIP_ERROR Decode(TLV::TLVReader & reader); }; }; // namespace GetCredentialStatusResponse diff --git a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp index e51e3eaa80e166..05c103395826c0 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp +++ b/zzz_generated/chip-tool/zap-generated/cluster/logging/DataModelLogger.cpp @@ -8560,6 +8560,7 @@ CHIP_ERROR DataModelLogger::LogValue(const char * label, size_t indent, ReturnErrorOnFailure(DataModelLogger::LogValue("creatorFabricIndex", indent + 1, value.creatorFabricIndex)); ReturnErrorOnFailure(DataModelLogger::LogValue("lastModifiedFabricIndex", indent + 1, value.lastModifiedFabricIndex)); ReturnErrorOnFailure(DataModelLogger::LogValue("nextCredentialIndex", indent + 1, value.nextCredentialIndex)); + ReturnErrorOnFailure(DataModelLogger::LogValue("credentialData", indent + 1, value.credentialData)); DataModelLogger::LogString(indent, "}"); return CHIP_NO_ERROR; } From e5276112fc31e2648d331089768451209f2c2fb4 Mon Sep 17 00:00:00 2001 From: William Date: Tue, 24 Sep 2024 18:05:41 +0100 Subject: [PATCH 17/19] =?UTF-8?q?Fixed=20the=20service=20area=20server=20t?= =?UTF-8?q?o=20check=20if=20there=20are=20any=20selected=20area=E2=80=A6?= =?UTF-8?q?=20(#35722)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed the service area server to check if there are any selected areas when hadling the skip area command. * Restyled by clang-format * Restyled by autopep8 * Update src/python_testing/TC_SEAR_1_5.py Co-authored-by: Petru Lauric <81822411+plauric@users.noreply.github.com> --------- Co-authored-by: Restyled.io Co-authored-by: Petru Lauric <81822411+plauric@users.noreply.github.com> --- .../service-area-server.cpp | 13 +++++++++--- src/python_testing/TC_SEAR_1_5.py | 20 +++++++++++-------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/app/clusters/service-area-server/service-area-server.cpp b/src/app/clusters/service-area-server/service-area-server.cpp index 55ee2ab27c9943..b474d8ee87df95 100644 --- a/src/app/clusters/service-area-server/service-area-server.cpp +++ b/src/app/clusters/service-area-server/service-area-server.cpp @@ -378,12 +378,19 @@ void Instance::HandleSkipAreaCmd(HandlerContext & ctx, const Commands::SkipArea: ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); }; - // The SkippedArea field SHALL match an entry in the SupportedAreas list. - // If the Status field is set to InvalidAreaList, the StatusText field SHALL be an empty string. + // If the SelectedAreas attribute is empty, the SkipAreaResponse command’s Status field SHALL indicate InvalidAreaList. + if (GetNumberOfSelectedAreas() == 0) + { + exitResponse(SkipAreaStatus::kInvalidAreaList, ""_span); + return; + } + + // If the SkippedArea field does not match an entry in the SupportedAreas attribute, the SkipAreaResponse command’s Status field + // SHALL indicate InvalidSkippedArea. if (!mStorageDelegate->IsSupportedArea(req.skippedArea)) { ChipLogError(Zcl, "SkippedArea (%" PRIu32 ") is not in the SupportedAreas attribute.", req.skippedArea); - exitResponse(SkipAreaStatus::kInvalidAreaList, ""_span); + exitResponse(SkipAreaStatus::kInvalidSkippedArea, ""_span); return; } diff --git a/src/python_testing/TC_SEAR_1_5.py b/src/python_testing/TC_SEAR_1_5.py index 50b9080dff08c2..d4704d686a61e4 100644 --- a/src/python_testing/TC_SEAR_1_5.py +++ b/src/python_testing/TC_SEAR_1_5.py @@ -115,26 +115,30 @@ async def test_TC_SEAR_1_5(self): if self.check_pics("SEAR.S.M.INVALID_STATE_FOR_SKIP") and self.check_pics("SEAR.S.M.HAS_MANUAL_SKIP_STATE_CONTROL"): test_step = "Manually intervene to put the device in a state that prevents it from executing the SkipArea command \ - (e.g. set CurrentArea to null or make it not operate, i.e. be in the idle state)" + (e.g. set CurrentArea to null or make it not operate, i.e. be in the idle state). Ensure that SelectedArea is not empty." self.print_step("3", test_step) - if not self.is_ci: + if self.is_ci: + await self.send_single_cmd(cmd=Clusters.Objects.ServiceArea.Commands.SelectAreas(newAreas=[7]), + endpoint=self.endpoint) + else: self.wait_for_user_input(prompt_msg=f"{test_step}, and press Enter when done.\n") - await self.send_cmd_skip_area_expect_response(step=4, skipped_area=valid_area_id, - expected_response=Clusters.ServiceArea.Enums.SkipAreaStatus.kInvalidInMode) + await self.send_cmd_skip_area_expect_response(step=4, skipped_area=valid_area_id, + expected_response=Clusters.ServiceArea.Enums.SkipAreaStatus.kInvalidInMode) if self.check_pics("SEAR.S.M.NO_SELAREA_FOR_SKIP") and self.check_pics("SEAR.S.M.HAS_MANUAL_SKIP_STATE_CONTROL"): test_step = "Manually intervene to put the device in a state where the state would allow it to execute the SkipArea command, \ if SelectedAreas wasn't empty, and SelectedAreas is empty" self.print_step("5", test_step) if self.is_ci: + self.write_to_app_pipe({"Name": "Reset"}) await self.send_single_cmd(cmd=Clusters.Objects.RvcRunMode.Commands.ChangeToMode(newMode=1), endpoint=self.endpoint) else: self.wait_for_user_input(prompt_msg=f"{test_step}, and press Enter when done.\n") - await self.send_cmd_skip_area_expect_response(step=6, skipped_area=valid_area_id, - expected_response=Clusters.ServiceArea.Enums.SkipAreaStatus.kInvalidAreaList) + await self.send_cmd_skip_area_expect_response(step=6, skipped_area=valid_area_id, + expected_response=Clusters.ServiceArea.Enums.SkipAreaStatus.kInvalidAreaList) if self.check_pics("SEAR.S.M.VALID_STATE_FOR_SKIP") and self.check_pics("SEAR.S.M.HAS_MANUAL_SKIP_STATE_CONTROL"): test_step = "Manually intervene to put the device in a state that allows it to execute the SkipArea command" @@ -148,8 +152,8 @@ async def test_TC_SEAR_1_5(self): else: self.wait_for_user_input(prompt_msg=f"{test_step}, and press Enter when done.\n") - await self.send_cmd_skip_area_expect_response(step=8, skipped_area=invalid_area_id, - expected_response=Clusters.ServiceArea.Enums.SkipAreaStatus.kInvalidSkippedArea) + await self.send_cmd_skip_area_expect_response(step=8, skipped_area=invalid_area_id, + expected_response=Clusters.ServiceArea.Enums.SkipAreaStatus.kInvalidSkippedArea) if not self.check_pics("SEAR.S.M.VALID_STATE_FOR_SKIP"): return From 222338e7914407e86b0e38aefe0077395b8bb3af Mon Sep 17 00:00:00 2001 From: Junior Martinez <67972863+jmartinez-silabs@users.noreply.github.com> Date: Tue, 24 Sep 2024 15:28:47 -0400 Subject: [PATCH 18/19] [Silabs] Fix some uart cli hang (#35723) * Add macros to abstact eusart api between series * Fix for uart cpp with irq handling with series3. Tweak uart and shell task priority. * [MATTER-4132]force implementation of _read and _write from newlib to use our UartConsole api when SILABS_LOG_OUT_UART is enabled * remove segger_rtt_syscalls when uartlog is enabled * Apply suggestions from code review Co-authored-by: Andrei Litvin * Restyled by gn --------- Co-authored-by: Andrei Litvin Co-authored-by: Restyled.io --- examples/platform/silabs/syscalls_stubs.cpp | 42 ++++++++++--- examples/platform/silabs/uart.cpp | 68 ++++++++++++++++----- src/lib/shell/streamer_silabs.cpp | 8 ++- third_party/silabs/SiWx917_sdk.gni | 6 +- third_party/silabs/efr32_sdk.gni | 5 +- 5 files changed, 103 insertions(+), 26 deletions(-) diff --git a/examples/platform/silabs/syscalls_stubs.cpp b/examples/platform/silabs/syscalls_stubs.cpp index 685bd63f567bb5..b5095bcf6731a5 100644 --- a/examples/platform/silabs/syscalls_stubs.cpp +++ b/examples/platform/silabs/syscalls_stubs.cpp @@ -38,6 +38,7 @@ extern "C" { #include "uart.h" #endif +int _open(char * path, int flags, ...); int _close(int file); int _fstat(int file, struct stat * st); int _isatty(int file); @@ -45,6 +46,23 @@ int _lseek(int file, int ptr, int dir); int _read(int file, char * ptr, int len); int _write(int file, const char * ptr, int len); +/************************************************************************** + * @brief + * Open a file. + * + * @param[in] file + * File you want to open. + * + * @return + * Returns -1 since there is not logic here to open file. + **************************************************************************/ + +int __attribute__((weak)) _open(char * path, int flags, ...) +{ + /* Pretend like we always fail */ + return -1; +} + /************************************************************************** * @brief * Close a file. @@ -170,17 +188,22 @@ int __attribute__((weak)) _lseek(int file, int ptr, int dir) * @return * Number of characters that have been read. *************************************************************************/ -int __attribute__((weak)) _read(int file, char * ptr, int len) +#if SILABS_LOG_OUT_UART +int _read(int file, char * ptr, int len) { (void) file; -#if SILABS_LOG_OUT_UART return uartConsoleRead(ptr, len); +} #else +int __attribute__((weak)) _read(int file, char * ptr, int len) +{ + (void) file; (void) ptr; (void) len; -#endif + return 0; } +#endif // SILABS_LOG_OUT_UART /************************************************************************** * @brief @@ -198,17 +221,20 @@ int __attribute__((weak)) _read(int file, char * ptr, int len) * @return * Number of characters that have been written. **************************************************************************/ -int __attribute__((weak)) _write(int file, const char * ptr, int len) +#if SILABS_LOG_OUT_UART +int _write(int file, const char * ptr, int len) { (void) file; -#if SILABS_LOG_OUT_UART - uartConsoleWrite(ptr, len); + return uartConsoleWrite(ptr, len); +} #else +int __attribute__((weak)) _write(int file, const char * ptr, int len) +{ + (void) file; (void) ptr; -#endif - return len; } +#endif // SILABS_LOG_OUT_UART #ifdef __cplusplus } diff --git a/examples/platform/silabs/uart.cpp b/examples/platform/silabs/uart.cpp index a05dd706e3a82f..a43a23fa2cd814 100644 --- a/examples/platform/silabs/uart.cpp +++ b/examples/platform/silabs/uart.cpp @@ -40,8 +40,12 @@ extern "C" { #include "rsi_rom_egpio.h" #include "sl_si91x_usart.h" #else // For EFR32 +#if (_SILICON_LABS_32B_SERIES < 3) #include "em_core.h" #include "em_usart.h" +#else +#include "sl_hal_eusart.h" +#endif //_SILICON_LABS_32B_SERIES #include "uartdrv.h" #ifdef SL_BOARD_NAME #include "sl_board_control.h" @@ -86,11 +90,34 @@ extern "C" { #define USART_IRQ HELPER2(SL_UARTDRV_EUSART_VCOM_PERIPHERAL_NO) #define USART_IRQHandler HELPER4(SL_UARTDRV_EUSART_VCOM_PERIPHERAL_NO) #define vcom_handle sl_uartdrv_eusart_vcom_handle + +#if (_SILICON_LABS_32B_SERIES < 3) +#define EUSART_INT_ENABLE EUSART_IntEnable +#define EUSART_INT_DISABLE EUSART_IntDisable +#define EUSART_INT_CLEAR EUSART_IntClear +#define EUSART_CLEAR_RX +#define EUSART_GET_PENDING_INT EUSART_IntGet +#define EUSART_ENABLE(eusart) EUSART_Enable(eusart, eusartEnable) +#else +#define EUSART_INT_ENABLE sl_hal_eusart_enable_interrupts +#define EUSART_INT_DISABLE sl_hal_eusart_disable_interrupts +#define EUSART_INT_SET sl_hal_eusart_set_interrupts +#define EUSART_INT_CLEAR sl_hal_eusart_clear_interrupts +#define EUSART_CLEAR_RX sl_hal_eusart_clear_rx +#define EUSART_GET_PENDING_INT sl_hal_eusart_get_pending_interrupts +#define EUSART_ENABLE(eusart) \ + { \ + sl_hal_eusart_enable(eusart); \ + sl_hal_eusart_enable_tx(eusart); \ + sl_hal_eusart_enable_rx(eusart); \ + } +#endif //_SILICON_LABS_32B_SERIES + #else #define USART_IRQ HELPER2(SL_UARTDRV_USART_VCOM_PERIPHERAL_NO) #define USART_IRQHandler HELPER4(SL_UARTDRV_USART_VCOM_PERIPHERAL_NO) #define vcom_handle sl_uartdrv_usart_vcom_handle -#endif // EFR32MG24 +#endif // SL_CATALOG_UARTDRV_EUSART_PRESENT namespace { // In order to reduce the probability of data loss during the dmaFull callback handler we use @@ -118,7 +145,11 @@ typedef struct #if SILABS_LOG_OUT_UART #define UART_MAX_QUEUE_SIZE 125 #else +#if (_SILICON_LABS_32B_SERIES < 3) #define UART_MAX_QUEUE_SIZE 25 +#else +#define UART_MAX_QUEUE_SIZE 50 +#endif #endif #ifdef CHIP_CONFIG_LOG_MESSAGE_MAX_SIZE @@ -138,13 +169,7 @@ constexpr osThreadAttr_t kUartTaskAttr = { .name = "UART", .cb_size = osThreadCbSize, .stack_mem = uartStack, .stack_size = kUartTaskSize, -#if SLI_SI91X_MCU_INTERFACE - // Reducing the priority of the UART task to avoid priority inversion - .priority = osPriorityNormal -#else - .priority = osPriorityRealtime -#endif // SLI_SI91X_MCU_INTERFACE -}; + .priority = osPriorityBelowNormal }; typedef struct { @@ -309,16 +334,17 @@ void uartConsoleInit(void) #ifdef SL_CATALOG_UARTDRV_EUSART_PRESENT // Clear previous RX interrupts - EUSART_IntClear(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL); + EUSART_INT_CLEAR(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, (EUSART_IF_RXFL | EUSART_IF_RXOF)); + EUSART_CLEAR_RX(SL_UARTDRV_EUSART_VCOM_PERIPHERAL); // Enable RX interrupts - EUSART_IntEnable(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL); + EUSART_INT_ENABLE(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL); // Enable EUSART - EUSART_Enable(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, eusartEnable); + EUSART_ENABLE(SL_UARTDRV_EUSART_VCOM_PERIPHERAL); #else USART_IntEnable(SL_UARTDRV_USART_VCOM_PERIPHERAL, USART_IF_RXDATAV); -#endif // EFR32MG24 +#endif // SL_CATALOG_UARTDRV_EUSART_PRESENT #endif // SLI_SI91X_MCU_INTERFACE == 0 } @@ -344,9 +370,15 @@ void USART_IRQHandler(void) #elif !defined(PW_RPC_ENABLED) && !defined(SL_WIFI) otSysEventSignalPending(); #endif - #ifdef SL_CATALOG_UARTDRV_EUSART_PRESENT - EUSART_IntClear(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL); + // disable RXFL IRQ until data read by uartConsoleRead + EUSART_INT_DISABLE(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL); + EUSART_INT_CLEAR(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL); + + if (EUSART_GET_PENDING_INT(SL_UARTDRV_EUSART_VCOM_PERIPHERAL) & EUSART_IF_RXOF) + { + EUSART_CLEAR_RX(SL_UARTDRV_EUSART_VCOM_PERIPHERAL); + } #endif } @@ -418,7 +450,8 @@ int16_t uartConsoleWrite(const char * Buf, uint16_t BufLength) memcpy(workBuffer.data, Buf, BufLength); workBuffer.length = BufLength; - if (osMessageQueuePut(sUartTxQueue, &workBuffer, osPriorityNormal, 0) == osOK) + // this is usually a command response. Wait on queue if full. + if (osMessageQueuePut(sUartTxQueue, &workBuffer, osPriorityNormal, osWaitForever) == osOK) { return BufLength; } @@ -445,6 +478,7 @@ int16_t uartLogWrite(const char * log, uint16_t length) memcpy(workBuffer.data + length, "\r\n", 2); workBuffer.length = length + 2; + // Don't wait when queue is full. Drop the log and return UART_CONSOLE_ERR if (osMessageQueuePut(sUartTxQueue, &workBuffer, osPriorityNormal, 0) == osOK) { return length; @@ -462,6 +496,10 @@ int16_t uartConsoleRead(char * Buf, uint16_t NbBytesToRead) { uint8_t * data; +#ifdef SL_CATALOG_UARTDRV_EUSART_PRESENT + EUSART_INT_ENABLE(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL); +#endif + if (Buf == NULL || NbBytesToRead < 1) { return UART_CONSOLE_ERR; diff --git a/src/lib/shell/streamer_silabs.cpp b/src/lib/shell/streamer_silabs.cpp index c6dcdf7320b6a5..014649cdb8349b 100644 --- a/src/lib/shell/streamer_silabs.cpp +++ b/src/lib/shell/streamer_silabs.cpp @@ -47,7 +47,13 @@ ssize_t streamer_efr_read(streamer_t * streamer, char * buffer, size_t length) ssize_t streamer_efr_write(streamer_t * streamer, const char * buffer, size_t length) { (void) streamer; - return uartConsoleWrite(buffer, (uint16_t) length); + int16_t bytesWritten = uartConsoleWrite(buffer, (uint16_t) length); + if (bytesWritten < 0) // The Write failed + { + bytesWritten = 0; + } + + return bytesWritten; } static streamer_t streamer_efr = { diff --git a/third_party/silabs/SiWx917_sdk.gni b/third_party/silabs/SiWx917_sdk.gni index 67428f518cae68..d338ea7d0a9162 100644 --- a/third_party/silabs/SiWx917_sdk.gni +++ b/third_party/silabs/SiWx917_sdk.gni @@ -773,8 +773,12 @@ template("siwx917_sdk") { public_deps = [ "${segger_rtt_root}:segger_rtt", "${segger_rtt_root}:segger_rtt_printf", - "${segger_rtt_root}:segger_rtt_syscalls", ] + + if (!sl_uart_log_output) { + public_deps += [ "${segger_rtt_root}:segger_rtt_syscalls" ] + } + if (chip_crypto == "platform") { if (sl_si91x_crypto_flavor == "tinycrypt") { public_deps += [ ":siwx917_tinycrypt" ] diff --git a/third_party/silabs/efr32_sdk.gni b/third_party/silabs/efr32_sdk.gni index 9a29ad6a05aa04..470c812505f966 100644 --- a/third_party/silabs/efr32_sdk.gni +++ b/third_party/silabs/efr32_sdk.gni @@ -1072,9 +1072,12 @@ template("efr32_sdk") { ":efr32_mbedtls_config", "${segger_rtt_root}:segger_rtt", "${segger_rtt_root}:segger_rtt_printf", - "${segger_rtt_root}:segger_rtt_syscalls", ] + if (!sl_uart_log_output) { + public_deps += [ "${segger_rtt_root}:segger_rtt_syscalls" ] + } + if (defined(invoker.sources)) { sources += invoker.sources } From 792895d19eae6593c1c016bfefa804a694729e2f Mon Sep 17 00:00:00 2001 From: C Freeman Date: Tue, 24 Sep 2024 12:54:56 -0700 Subject: [PATCH 19/19] TC-OPSTATE-2.5: Force expire session on reboot (#35712) If the DUT has rebooted, the TH will need to establish the session again, which means expiring the current. In a real product, a fail on the case would trigger a retry, but it's not clear that we want that in the TH because it can paper over problems where the DUT is crashing. This is an intentional reboot, wihch is different. Probably not caught in CI / QA because the CI app doesn't actually reboot. --- src/python_testing/TC_OpstateCommon.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/python_testing/TC_OpstateCommon.py b/src/python_testing/TC_OpstateCommon.py index e0e252ea180eb0..060f5d2f53ed30 100644 --- a/src/python_testing/TC_OpstateCommon.py +++ b/src/python_testing/TC_OpstateCommon.py @@ -1112,10 +1112,11 @@ async def TEST_TC_OPSTATE_BASE_2_5(self, endpoint=1): # STEP 11: Restart DUT self.step(11) - # In CI environment, the STOP coommand (step 8) already resets the variables. Only ask for + # In CI environment, the STOP command (step 8) already resets the variables. Only ask for # reboot outside CI environment. if not self.is_ci: self.wait_for_user_input(prompt_msg="Restart DUT. Press Enter when ready.\n") + self.default_controller.ExpireSessions(self.dut_node_id) # STEP 12: TH waits for {PIXIT.WAITTIME.REBOOT} self.step(12)