From a2f18c90671eaa3675e23c6dfa08f68ba80ab836 Mon Sep 17 00:00:00 2001 From: Karsten Sperling <113487422+ksperling-apple@users.noreply.github.com> Date: Tue, 3 Sep 2024 23:30:55 +1200 Subject: [PATCH] Add TBRM cluster to placeholder app1 (#35362) Fixes #35330 --- examples/placeholder/linux/apps/app1/BUILD.gn | 1 + .../placeholder/linux/apps/app1/config.matter | 65 +++++ .../placeholder/linux/apps/app1/config.zap | 245 ++++++++++++++++++ .../linux/thread-border-router-management.cpp | 85 ++++++ 4 files changed, 396 insertions(+) create mode 100644 examples/placeholder/linux/thread-border-router-management.cpp diff --git a/examples/placeholder/linux/apps/app1/BUILD.gn b/examples/placeholder/linux/apps/app1/BUILD.gn index f16b9301ce3a90..aba1e870f7a041 100644 --- a/examples/placeholder/linux/apps/app1/BUILD.gn +++ b/examples/placeholder/linux/apps/app1/BUILD.gn @@ -30,6 +30,7 @@ source_set("app1") { "../../resource-monitoring-delegates.cpp", "../../src/bridged-actions-stub.cpp", "../../static-supported-modes-manager.cpp", + "../../thread-border-router-management.cpp", ] public_deps = [ ":configuration" ] diff --git a/examples/placeholder/linux/apps/app1/config.matter b/examples/placeholder/linux/apps/app1/config.matter index a92f0a495885f3..96c3b7220841be 100644 --- a/examples/placeholder/linux/apps/app1/config.matter +++ b/examples/placeholder/linux/apps/app1/config.matter @@ -6716,6 +6716,50 @@ cluster OccupancySensing = 1030 { readonly attribute int16u clusterRevision = 65533; } +/** 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; +} + /** This cluster provides an interface for controlling the current Channel on a device. */ cluster Channel = 1284 { revision 2; @@ -9619,6 +9663,27 @@ endpoint 1 { callback attribute featureMap; callback attribute clusterRevision default = 5; } + + 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; + } } diff --git a/examples/placeholder/linux/apps/app1/config.zap b/examples/placeholder/linux/apps/app1/config.zap index d7cad4f031e5c3..21f2a00eb50e9b 100644 --- a/examples/placeholder/linux/apps/app1/config.zap +++ b/examples/placeholder/linux/apps/app1/config.zap @@ -15107,6 +15107,251 @@ "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 + } + ] } ] } diff --git a/examples/placeholder/linux/thread-border-router-management.cpp b/examples/placeholder/linux/thread-border-router-management.cpp new file mode 100644 index 00000000000000..3ab7dbd707567f --- /dev/null +++ b/examples/placeholder/linux/thread-border-router-management.cpp @@ -0,0 +1,85 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include + +using namespace chip; +using namespace chip::literals; +using namespace chip::app; +using namespace chip::app::Clusters; + +namespace { +class FakeBorderRouterDelegate final : public ThreadBorderRouterManagement::Delegate +{ + CHIP_ERROR Init(AttributeChangeCallback * attributeChangeCallback) override { return CHIP_NO_ERROR; } + + bool GetPanChangeSupported() override { return true; } + + void GetBorderRouterName(MutableCharSpan & borderRouterName) override + { + CopyCharSpanToMutableCharSpan("netman-br"_span, borderRouterName); + } + + CHIP_ERROR GetBorderAgentId(MutableByteSpan & borderAgentId) override + { + static constexpr uint8_t kBorderAgentId[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + VerifyOrReturnError(borderAgentId.size() == 16, CHIP_ERROR_INVALID_ARGUMENT); + return CopySpanToMutableSpan(ByteSpan(kBorderAgentId), borderAgentId); + } + + uint16_t GetThreadVersion() override { return /* Thread 1.3.1 */ 5; } + + bool GetInterfaceEnabled() override { return false; } + + CHIP_ERROR GetDataset(Thread::OperationalDataset & dataset, DatasetType type) override { return CHIP_ERROR_NOT_FOUND; } + + void SetActiveDataset(const Thread::OperationalDataset & activeDataset, uint32_t sequenceNum, + ActivateDatasetCallback * callback) override + { + ChipLogAutomation("SetActiveDataset"); + callback->OnActivateDatasetComplete(sequenceNum, CHIP_NO_ERROR); + } + + CHIP_ERROR CommitActiveDataset() override { return CHIP_NO_ERROR; } + CHIP_ERROR RevertActiveDataset() override { return CHIP_NO_ERROR; } + + CHIP_ERROR SetPendingDataset(const Thread::OperationalDataset & pendingDataset) override + { + ChipLogAutomation("SetPendingDataset"); + return CHIP_NO_ERROR; + } +}; + +FakeBorderRouterDelegate gBorderRouterDelegate{}; +} // namespace + +std::optional gThreadBorderRouterManagementServer; +void emberAfThreadBorderRouterManagementClusterInitCallback(EndpointId endpoint) +{ + VerifyOrDie(!gThreadBorderRouterManagementServer); + gThreadBorderRouterManagementServer.emplace(endpoint, &gBorderRouterDelegate, Server::GetInstance().GetFailSafeContext()) + .Init(); +}