diff --git a/.github/.wordlist.txt b/.github/.wordlist.txt index c9d72a3179beee..3245626bebaa79 100644 --- a/.github/.wordlist.txt +++ b/.github/.wordlist.txt @@ -1401,3 +1401,8 @@ kManage kOperate kView xFFFFFFFD +NAMESERVER +UTF +localedef +nameserver +nmcli diff --git a/examples/light-switch-app/efr32/README.md b/examples/light-switch-app/efr32/README.md index d73a2ab2fc9b63..641b6ddd55882b 100644 --- a/examples/light-switch-app/efr32/README.md +++ b/examples/light-switch-app/efr32/README.md @@ -271,6 +271,11 @@ combination with JLinkRTTClient as follows: - 'switch groups onoff off' : Sends On group command to bound group - 'switch groups onoff toggle' : Sends On group command to bound group + **_Binding Cluster_** + + - 'switch binding unicast ' : Creates a unicast binding + - 'switch binding group ' : Creates a group binding + * You can provision and control the Chip device using the python controller, [CHIPTool](https://github.com/project-chip/connectedhomeip/blob/master/examples/chip-tool/README.md) standalone, Android or iOS app @@ -280,7 +285,7 @@ combination with JLinkRTTClient as follows: ``` chip-tool pairing ble-thread 1 hex: 20202021 3840 - chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": [1], "targets": null }]' 0 + chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [], "targets": null }{"fabricIndex": 1, "privilege": 3, "authMode": 2, "subjects": [1], "targets": null }]' 0 chip-tool binding write binding '[{"fabricIndex": 1, "node": , "endpoint": 1, "cluster":6}]' 1 1 ``` @@ -304,6 +309,13 @@ combination with JLinkRTTClient as follows: chip-tool binding write binding '[{"fabricIndex": 1, "group": 257},{"fabricIndex": 1, "node": , "endpoint": 1, "cluster":6} ]' 1 1 ``` + To acquire the chip-tool node id, read the acl table right after + commissioning + + ``` + ./connectedhomeip/out/chip-tool/chip-tool accesscontrol read acl 0 + ``` + ### Notes - Depending on your network settings your router might not provide native ipv6 diff --git a/examples/light-switch-app/efr32/include/binding-handler.h b/examples/light-switch-app/efr32/include/binding-handler.h index 367b8962771b46..aed08be25eb5bc 100644 --- a/examples/light-switch-app/efr32/include/binding-handler.h +++ b/examples/light-switch-app/efr32/include/binding-handler.h @@ -22,6 +22,7 @@ CHIP_ERROR InitBindingHandler(); void SwitchWorkerFunction(intptr_t context); +void BindingWorkerFunction(intptr_t context); struct BindingCommandData { diff --git a/examples/light-switch-app/efr32/src/binding-handler.cpp b/examples/light-switch-app/efr32/src/binding-handler.cpp index 24fc87e5b9a7fa..d58484e1b6dcc0 100644 --- a/examples/light-switch-app/efr32/src/binding-handler.cpp +++ b/examples/light-switch-app/efr32/src/binding-handler.cpp @@ -23,6 +23,7 @@ #include "app/server/Server.h" #include "controller/InvokeInteraction.h" #include "platform/CHIPDeviceLayer.h" +#include #include #if defined(ENABLE_CHIP_SHELL) @@ -41,9 +42,11 @@ using Shell::streamer_printf; Engine sShellSwitchSubCommands; Engine sShellSwitchOnOffSubCommands; -Engine sShellSwitchGroupsSubCommands; +Engine sShellSwitchGroupsSubCommands; Engine sShellSwitchGroupsOnOffSubCommands; + +Engine sShellSwitchBindingSubCommands; #endif // defined(ENABLE_CHIP_SHELL) namespace { @@ -202,6 +205,57 @@ CHIP_ERROR ToggleSwitchCommandHandler(int argc, char ** argv) return CHIP_NO_ERROR; } +/******************************************************** + * bind switch shell functions + *********************************************************/ + +CHIP_ERROR BindingHelpHandler(int argc, char ** argv) +{ + sShellSwitchBindingSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr); + return CHIP_NO_ERROR; +} + +CHIP_ERROR BindingSwitchCommandHandler(int argc, char ** argv) +{ + if (argc == 0) + { + return BindingHelpHandler(argc, argv); + } + + return sShellSwitchBindingSubCommands.ExecCommand(argc, argv); +} + +CHIP_ERROR BindingGroupBindCommandHandler(int argc, char ** argv) +{ + VerifyOrReturnError(argc == 2, CHIP_ERROR_INVALID_ARGUMENT); + + EmberBindingTableEntry * entry = Platform::New(); + entry->type = EMBER_MULTICAST_BINDING; + entry->fabricIndex = atoi(argv[0]); + entry->groupId = atoi(argv[1]); + entry->local = 1; // Hardcoded to endpoint 1 for now + entry->clusterId.SetValue(6); // Hardcoded to OnOff cluster for now + + DeviceLayer::PlatformMgr().ScheduleWork(BindingWorkerFunction, reinterpret_cast(entry)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR BindingUnicastBindCommandHandler(int argc, char ** argv) +{ + VerifyOrReturnError(argc == 3, CHIP_ERROR_INVALID_ARGUMENT); + + EmberBindingTableEntry * entry = Platform::New(); + entry->type = EMBER_UNICAST_BINDING; + entry->fabricIndex = atoi(argv[0]); + entry->nodeId = atoi(argv[1]); + entry->local = 1; // Hardcoded to endpoint 1 for now + entry->remote = atoi(argv[2]); + entry->clusterId.SetValue(6)); // Hardcode to OnOff cluster for now + + DeviceLayer::PlatformMgr().ScheduleWork(BindingWorkerFunction, reinterpret_cast(entry)); + return CHIP_NO_ERROR; +} + /******************************************************** * Groups switch shell functions *********************************************************/ @@ -285,7 +339,7 @@ static void RegisterSwitchCommands() { &SwitchHelpHandler, "help", "Usage: switch " }, { &OnOffSwitchCommandHandler, "onoff", " Usage: switch onoff " }, { &GroupsSwitchCommandHandler, "groups", "Usage: switch groups " }, - + { &BindingSwitchCommandHandler, "binding", "Usage: switch binding " } }; static const shell_command_t sSwitchOnOffSubCommands[] = { @@ -299,19 +353,26 @@ static void RegisterSwitchCommands() { &GroupsOnOffSwitchCommandHandler, "onoff", "Usage: switch groups onoff " } }; - static const shell_command_t sSwichGroupsOnOffSubCommands[] = { + static const shell_command_t sSwitchGroupsOnOffSubCommands[] = { { &GroupsOnOffHelpHandler, "help", "Usage: switch groups onoff " }, { &GroupOnSwitchCommandHandler, "on", "Sends on command to bound group" }, { &GroupOffSwitchCommandHandler, "off", "Sends off command to bound group" }, { &GroupToggleSwitchCommandHandler, "toggle", "Sends toggle command to group" } }; + static const shell_command_t sSwitchBindingSubCommands[] = { + { &BindingHelpHandler, "help", "Usage: switch binding " }, + { &BindingGroupBindCommandHandler, "group", "Usage: switch binding group " }, + { &BindingUnicastBindCommandHandler, "unicast", "Usage: switch binding group " } + }; + static const shell_command_t sSwitchCommand = { &SwitchCommandHandler, "switch", "Light-switch commands. Usage: switch " }; - sShellSwitchGroupsOnOffSubCommands.RegisterCommands(sSwichGroupsOnOffSubCommands, ArraySize(sSwichGroupsOnOffSubCommands)); + sShellSwitchGroupsOnOffSubCommands.RegisterCommands(sSwitchGroupsOnOffSubCommands, ArraySize(sSwitchGroupsOnOffSubCommands)); sShellSwitchOnOffSubCommands.RegisterCommands(sSwitchOnOffSubCommands, ArraySize(sSwitchOnOffSubCommands)); sShellSwitchGroupsSubCommands.RegisterCommands(sSwitchGroupsSubCommands, ArraySize(sSwitchGroupsSubCommands)); + sShellSwitchBindingSubCommands.RegisterCommands(sSwitchBindingSubCommands, ArraySize(sSwitchBindingSubCommands)); sShellSwitchSubCommands.RegisterCommands(sSwitchSubCommands, ArraySize(sSwitchSubCommands)); Engine::Root().RegisterCommands(&sSwitchCommand, 1); @@ -342,6 +403,16 @@ void SwitchWorkerFunction(intptr_t context) Platform::Delete(data); } +void BindingWorkerFunction(intptr_t context) +{ + VerifyOrReturn(context != 0, ChipLogError(NotSpecified, "BindingWorkerFunction - Invalid work data")); + + EmberBindingTableEntry * entry = reinterpret_cast(context); + AddBindingEntry(*entry); + + Platform::Delete(entry); +} + CHIP_ERROR InitBindingHandler() { // The initialization of binding manager will try establishing connection with unicast peers diff --git a/src/app/clusters/bindings/bindings.cpp b/src/app/clusters/bindings/bindings.cpp index c532c68cd65325..d13c1621416716 100644 --- a/src/app/clusters/bindings/bindings.cpp +++ b/src/app/clusters/bindings/bindings.cpp @@ -25,11 +25,9 @@ #include #include #include -#include +#include #include -#include #include - using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; @@ -86,7 +84,7 @@ CHIP_ERROR CheckValidBindingList(const DecodableBindingListType & bindingList, F return CHIP_NO_ERROR; } -void AddBindingEntry(const TargetStructType & entry, EndpointId localEndpoint) +void CreateBindingEntry(const TargetStructType & entry, EndpointId localEndpoint) { EmberBindingTableEntry bindingEntry; @@ -98,18 +96,9 @@ void AddBindingEntry(const TargetStructType & entry, EndpointId localEndpoint) { bindingEntry = EmberBindingTableEntry::ForNode(entry.fabricIndex, entry.node.Value(), localEndpoint, entry.endpoint.Value(), entry.cluster); - CHIP_ERROR err = BindingManager::GetInstance().UnicastBindingCreated(entry.fabricIndex, entry.node.Value()); - if (err != CHIP_NO_ERROR) - { - // Unicast connection failure can happen if peer is offline. We'll retry connection on-demand. - ChipLogProgress( - Zcl, "Binding: Failed to create session for unicast binding to device " ChipLogFormatX64 ": %" CHIP_ERROR_FORMAT, - ChipLogValueX64(entry.node.Value()), err.Format()); - } } - BindingTable::GetInstance().Add(bindingEntry); - BindingManager::GetInstance().NotifyBindingAdded(bindingEntry); + AddBindingEntry(bindingEntry); } CHIP_ERROR BindingTableAccess::Read(const ConcreteReadAttributePath & path, AttributeValueEncoder & encoder) @@ -200,7 +189,7 @@ CHIP_ERROR BindingTableAccess::WriteBindingTable(const ConcreteDataAttributePath auto iter = newBindingList.begin(); while (iter.Next()) { - AddBindingEntry(iter.GetValue(), path.mEndpointId); + CreateBindingEntry(iter.GetValue(), path.mEndpointId); } return CHIP_NO_ERROR; } @@ -212,7 +201,7 @@ CHIP_ERROR BindingTableAccess::WriteBindingTable(const ConcreteDataAttributePath { return CHIP_IM_GLOBAL_STATUS(ConstraintError); } - AddBindingEntry(target, path.mEndpointId); + CreateBindingEntry(target, path.mEndpointId); return CHIP_NO_ERROR; } return CHIP_IM_GLOBAL_STATUS(UnsupportedWrite); @@ -223,3 +212,21 @@ void MatterBindingPluginServerInitCallback() { registerAttributeAccessOverride(&gAttrAccess); } + +void AddBindingEntry(const EmberBindingTableEntry & entry) +{ + if (entry.type == EMBER_UNICAST_BINDING) + { + CHIP_ERROR err = BindingManager::GetInstance().UnicastBindingCreated(entry.fabricIndex, entry.nodeId); + if (err != CHIP_NO_ERROR) + { + // Unicast connection failure can happen if peer is offline. We'll retry connection on-demand. + ChipLogProgress( + Zcl, "Binding: Failed to create session for unicast binding to device " ChipLogFormatX64 ": %" CHIP_ERROR_FORMAT, + ChipLogValueX64(entry.nodeId), err.Format()); + } + } + + BindingTable::GetInstance().Add(entry); + BindingManager::GetInstance().NotifyBindingAdded(entry); +} diff --git a/src/app/clusters/bindings/bindings.h b/src/app/clusters/bindings/bindings.h new file mode 100644 index 00000000000000..3d6d773cdbcd8c --- /dev/null +++ b/src/app/clusters/bindings/bindings.h @@ -0,0 +1,31 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include + +/** + * @brief appends a binding to the list of bindings + * This function is to be used when a device wants to add a binding to its own table + * If entry is a unicast binding, BindingManager will be notified and will establish a case session with the peer device + * Entry will be added to the binding table and persisted into storage + * BindingManager will be notified and the binding added callback will be called if it has been set + * + * @param entry binding to add + */ +void AddBindingEntry(const EmberBindingTableEntry & entry);