diff --git a/examples/all-clusters-app/mbed/CMakeLists.txt b/examples/all-clusters-app/mbed/CMakeLists.txt index cda04bca5e6733..a28dd60017e677 100644 --- a/examples/all-clusters-app/mbed/CMakeLists.txt +++ b/examples/all-clusters-app/mbed/CMakeLists.txt @@ -84,6 +84,7 @@ target_sources(${APP_TARGET} PRIVATE ${APP_CLUSTERS}/basic/basic.cpp ${APP_CLUSTERS}/bindings/BindingManager.cpp ${APP_CLUSTERS}/bindings/bindings.cpp + ${APP_CLUSTERS}/bindings/PendingNotificationMap.cpp ${APP_CLUSTERS}/on-off-server/on-off-server.cpp ${APP_CLUSTERS}/access-control-server/access-control-server.cpp ${APP_CLUSTERS}/account-login-server/account-login-server.cpp diff --git a/examples/lighting-app/telink/CMakeLists.txt b/examples/lighting-app/telink/CMakeLists.txt index 94e98c8be5290f..3d1e3699383a8d 100644 --- a/examples/lighting-app/telink/CMakeLists.txt +++ b/examples/lighting-app/telink/CMakeLists.txt @@ -74,6 +74,7 @@ target_sources(app PRIVATE ${CHIP_ROOT}/src/app/clusters/basic/basic.cpp ${CHIP_ROOT}/src/app/clusters/bindings/BindingManager.cpp ${CHIP_ROOT}/src/app/clusters/bindings/bindings.cpp + ${CHIP_ROOT}/src/app/clusters/bindings/PendingNotificationMap.cpp ${CHIP_ROOT}/src/app/clusters/descriptor/descriptor.cpp ${CHIP_ROOT}/src/app/clusters/identify-server/identify-server.cpp ${CHIP_ROOT}/src/app/clusters/diagnostic-logs-server/diagnostic-logs-server.cpp diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index 650b375145f69d..109fa7dc85d0a0 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -148,6 +148,8 @@ template("chip_data_model") { "${_app_root}/clusters/${cluster}/${cluster}.cpp", "${_app_root}/clusters/${cluster}/BindingManager.cpp", "${_app_root}/clusters/${cluster}/BindingManager.h", + "${_app_root}/clusters/${cluster}/PendingNotificationMap.cpp", + "${_app_root}/clusters/${cluster}/PendingNotificationMap.h", ] } else { sources += [ "${_app_root}/clusters/${cluster}/${cluster}.cpp" ] diff --git a/src/app/clusters/bindings/BindingManager.cpp b/src/app/clusters/bindings/BindingManager.cpp index 74ff018c7a8111..d1622042bb37cc 100644 --- a/src/app/clusters/bindings/BindingManager.cpp +++ b/src/app/clusters/bindings/BindingManager.cpp @@ -49,10 +49,37 @@ BindingFabricTableDelegate gFabricTableDelegate; } // namespace +namespace { + +chip::PeerId PeerIdForNode(chip::FabricTable & fabricTable, chip::FabricIndex fabric, chip::NodeId node) +{ + chip::FabricInfo * fabricInfo = fabricTable.FindFabricWithIndex(fabric); + if (fabricInfo == nullptr) + { + return chip::PeerId(); + } + return fabricInfo->GetPeerIdForNode(node); +} + +} // namespace + namespace chip { BindingManager BindingManager::sBindingManager; +CHIP_ERROR BindingManager::UnicastBindingCreated(const EmberBindingTableEntry & bindingEntry) +{ + return EstablishConnection(bindingEntry.fabricIndex, bindingEntry.nodeId); +} + +CHIP_ERROR BindingManager::UnicastBindingRemoved(uint8_t bindingEntryId) +{ + EmberBindingTableEntry entry{}; + emberGetBinding(bindingEntryId, &entry); + mPendingNotificationMap.RemoveEntry(bindingEntryId); + return CHIP_NO_ERROR; +} + void BindingManager::SetAppServer(Server * appServer) { mAppServer = appServer; @@ -63,9 +90,8 @@ CHIP_ERROR BindingManager::EstablishConnection(FabricIndex fabric, NodeId node) { VerifyOrReturnError(mAppServer != nullptr, CHIP_ERROR_INCORRECT_STATE); - FabricInfo * fabricInfo = mAppServer->GetFabricTable().FindFabricWithIndex(fabric); - VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_NOT_FOUND); - PeerId peer = fabricInfo->GetPeerIdForNode(node); + PeerId peer = PeerIdForNode(mAppServer->GetFabricTable(), fabric, node); + VerifyOrReturnError(peer.GetNodeId() != kUndefinedNodeId, CHIP_ERROR_NOT_FOUND); CHIP_ERROR error = mAppServer->GetCASESessionManager()->FindOrEstablishSession(peer, &mOnConnectedCallback, &mOnConnectionFailureCallback); if (error == CHIP_ERROR_NO_MEMORY) @@ -73,11 +99,13 @@ CHIP_ERROR BindingManager::EstablishConnection(FabricIndex fabric, NodeId node) // Release the least recently used entry // TODO: Some reference counting mechanism shall be added the CASESessionManager // so that other session clients don't get accidentally closed. - PendingNotificationEntry * entry = mPendingNotificationMap.FindLRUEntry(); - if (entry != nullptr) + FabricIndex fabricToRemove; + NodeId nodeToRemove; + if (mPendingNotificationMap.FindLRUConnectPeer(&fabricToRemove, &nodeToRemove) == CHIP_NO_ERROR) { - mAppServer->GetCASESessionManager()->ReleaseSession(entry->GetPeerId()); - mPendingNotificationMap.RemoveEntry(entry); + mPendingNotificationMap.RemoveAllEntriesForNode(fabricToRemove, nodeToRemove); + PeerId lruPeer = PeerIdForNode(mAppServer->GetFabricTable(), fabricToRemove, nodeToRemove); + mAppServer->GetCASESessionManager()->ReleaseSession(lruPeer); // Now retry error = mAppServer->GetCASESessionManager()->FindOrEstablishSession(peer, &mOnConnectedCallback, &mOnConnectionFailureCallback); @@ -94,33 +122,23 @@ void BindingManager::HandleDeviceConnected(void * context, OperationalDeviceProx void BindingManager::HandleDeviceConnected(OperationalDeviceProxy * device) { - mPendingNotificationMap.ForEachActiveObject([&](PendingNotificationEntry * entry) -> Loop { - if (entry->GetPeerId() == device->GetPeerId()) - { - SyncPendingNotificationsToPeer(device, entry); - } + FabricIndex fabricToRemove = kUndefinedFabricIndex; + NodeId nodeToRemove = kUndefinedNodeId; - return Loop::Continue; - }); -} - -void BindingManager::SyncPendingNotificationsToPeer(OperationalDeviceProxy * device, PendingNotificationEntry * pendingClusters) -{ - for (const ClusterPath & path : *pendingClusters) + for (const PendingNotificationEntry & pendingNotification : mPendingNotificationMap) { - ClusterId cluster = path.cluster; - EndpointId endpoint = path.endpoint; - for (uint8_t j = 0; j < EMBER_BINDING_TABLE_SIZE; j++) + EmberBindingTableEntry entry; + emberGetBinding(pendingNotification.mBindingEntryId, &entry); + + PeerId peer = PeerIdForNode(mAppServer->GetFabricTable(), entry.fabricIndex, entry.nodeId); + if (device->GetPeerId() == peer) { - EmberBindingTableEntry entry; - if (emberGetBinding(j, &entry) == EMBER_SUCCESS && entry.type == EMBER_UNICAST_BINDING && entry.clusterId == cluster && - entry.local == endpoint && mBoundDeviceChangedHandler) - { - mBoundDeviceChangedHandler(&entry, device, path.context); - } + fabricToRemove = entry.fabricIndex; + nodeToRemove = entry.nodeId; + mBoundDeviceChangedHandler(&entry, device, pendingNotification.mContext); } } - mPendingNotificationMap.RemoveEntry(pendingClusters); + mPendingNotificationMap.RemoveAllEntriesForNode(fabricToRemove, nodeToRemove); } void BindingManager::HandleDeviceConnectionFailure(void * context, PeerId peerId, CHIP_ERROR error) @@ -138,34 +156,10 @@ void BindingManager::HandleDeviceConnectionFailure(PeerId peerId, CHIP_ERROR err void BindingManager::FabricRemoved(CompressedFabricId compressedFabricId, FabricIndex fabricIndex) { - mPendingNotificationMap.ForEachActiveObject([&](PendingNotificationEntry * entry) { - if (entry->GetFabricIndex() == fabricIndex) - { - mPendingNotificationMap.RemoveEntry(entry); - return Loop::Break; - } - return Loop::Continue; - }); + mPendingNotificationMap.RemoveAllEntriesForFabric(fabricIndex); mAppServer->GetCASESessionManager()->ReleaseSessionForFabric(compressedFabricId); } -CHIP_ERROR BindingManager::LastUnicastBindingRemoved(FabricIndex fabricIndex, NodeId node) -{ - VerifyOrReturnError(mAppServer != nullptr, CHIP_ERROR_INCORRECT_STATE); - - FabricInfo * fabricInfo = mAppServer->GetFabricTable().FindFabricWithIndex(fabricIndex); - VerifyOrReturnError(fabricInfo != nullptr, CHIP_ERROR_NOT_FOUND); - PeerId peer = fabricInfo->GetPeerIdForNode(node); - PendingNotificationEntry * entry = mPendingNotificationMap.FindEntry(fabricIndex, node); - if (entry) - { - mPendingNotificationMap.RemoveEntry(entry); - } - - mAppServer->GetCASESessionManager()->ReleaseSession(peer); - return CHIP_NO_ERROR; -} - CHIP_ERROR BindingManager::NotifyBoundClusterChanged(EndpointId endpoint, ClusterId cluster, void * context) { VerifyOrReturnError(mAppServer != nullptr, CHIP_ERROR_INCORRECT_STATE); @@ -190,9 +184,7 @@ CHIP_ERROR BindingManager::NotifyBoundClusterChanged(EndpointId endpoint, Cluste } else { - // Enqueue pending cluster and establish connection - ReturnErrorOnFailure(mPendingNotificationMap.AddPendingNotification(entry.fabricIndex, entry.nodeId, endpoint, - cluster, context)); + mPendingNotificationMap.AddPendingNotification(i, context); ReturnErrorOnFailure(EstablishConnection(entry.fabricIndex, entry.nodeId)); } } @@ -205,46 +197,4 @@ CHIP_ERROR BindingManager::NotifyBoundClusterChanged(EndpointId endpoint, Cluste return CHIP_NO_ERROR; } -BindingManager::PendingNotificationEntry * BindingManager::PendingNotificationMap::FindLRUEntry() -{ - PendingNotificationEntry * lruEntry = nullptr; - mPendingNotificationMap.ForEachActiveObject([&](PendingNotificationEntry * entry) { - if (lruEntry == nullptr || lruEntry->GetLastUpdateTime() > entry->GetLastUpdateTime()) - { - lruEntry = entry; - } - return Loop::Continue; - }); - return lruEntry; -} - -BindingManager::PendingNotificationEntry * BindingManager::PendingNotificationMap::FindEntry(FabricIndex fabricIndex, NodeId node) -{ - PendingNotificationEntry * foundEntry = nullptr; - mPendingNotificationMap.ForEachActiveObject([&](PendingNotificationEntry * entry) { - if (entry->GetFabricIndex() == fabricIndex && entry->GetNodeId() == node) - { - foundEntry = entry; - return Loop::Break; - } - return Loop::Continue; - }); - return foundEntry; -} - -CHIP_ERROR BindingManager::PendingNotificationMap::AddPendingNotification(FabricIndex fabric, NodeId node, EndpointId endpoint, - ClusterId cluster, void * context) -{ - PendingNotificationEntry * entry = FindEntry(fabric, node); - - if (entry == nullptr) - { - entry = mPendingNotificationMap.CreateObject(fabric, node); - VerifyOrReturnError(entry != nullptr, CHIP_ERROR_NO_MEMORY); - } - entry->AddPendingNotification(endpoint, cluster, context); - entry->Touch(); - return CHIP_NO_ERROR; -} - } // namespace chip diff --git a/src/app/clusters/bindings/BindingManager.h b/src/app/clusters/bindings/BindingManager.h index fd0ade9d1f5772..eb87864a127085 100644 --- a/src/app/clusters/bindings/BindingManager.h +++ b/src/app/clusters/bindings/BindingManager.h @@ -18,6 +18,7 @@ #pragma once #include +#include #include #include @@ -53,8 +54,6 @@ using BoundDeviceChangedHandler = void (*)(const EmberBindingTableEntry * bindin */ class BindingManager { - friend class PendingNotificationEntry; - public: BindingManager() : mOnConnectedCallback(HandleDeviceConnected, this), mOnConnectionFailureCallback(HandleDeviceConnectionFailure, this) @@ -68,19 +67,19 @@ class BindingManager * Notifies the BindingManager that a new unicast binding is created. * */ - CHIP_ERROR UnicastBindingCreated(FabricIndex fabric, NodeId node) { return EstablishConnection(fabric, node); } + CHIP_ERROR UnicastBindingCreated(const EmberBindingTableEntry & bindingEntry); /* - * Notifies the BindingManager that a fabric is removed from the device + * Notifies the BindingManager that a unicast binding is about to be removed from the given index. * */ - void FabricRemoved(CompressedFabricId compressedId, FabricIndex fabricIndex); + CHIP_ERROR UnicastBindingRemoved(uint8_t bindingEntryId); /* - * Notfies the BindingManager that the **last** unicast binding to a device has been removed. + * Notifies the BindingManager that a fabric is removed from the device * */ - CHIP_ERROR LastUnicastBindingRemoved(FabricIndex fabricIndex, NodeId node); + void FabricRemoved(CompressedFabricId compressedId, FabricIndex fabricIndex); /* * Notify a cluster change to **all** bound devices associated with the (endpoint, cluster) tuple. @@ -99,104 +98,6 @@ class BindingManager private: static BindingManager sBindingManager; - static constexpr uint8_t kMaxPendingNotifications = 3; - - struct ClusterPath - { - void * context; - ClusterId cluster; - EndpointId endpoint; - }; - - // A pending notification to be sent to a binding waiting for the CASE session to be established. - class PendingNotificationEntry - { - public: - PendingNotificationEntry(FabricIndex fabricIndex, NodeId node) : mNodeId(node), mFabricIndex(fabricIndex) {} - - PeerId GetPeerId() - { - PeerId peer; - if (BindingManager::GetInstance().mAppServer == nullptr) - { - return peer; - } - FabricInfo * fabric = BindingManager::GetInstance().mAppServer->GetFabricTable().FindFabricWithIndex(mFabricIndex); - if (fabric == nullptr) - { - return peer; - } - return fabric->GetPeerIdForNode(mNodeId); - } - - NodeId GetNodeId() { return mNodeId; } - - FabricIndex GetFabricIndex() { return mFabricIndex; } - - System::Clock::Timestamp GetLastUpdateTime() { return mLastUpdateTime; } - void Touch() { mLastUpdateTime = System::SystemClock().GetMonotonicTimestamp(); } - - ClusterPath * begin() { return &mPendingNotifications[0]; } - ClusterPath * end() { return &mPendingNotifications[mNumPendingNotifications]; } - - void AddPendingNotification(EndpointId endpoint, ClusterId cluster, void * context) - { - for (ClusterPath & path : *this) - { - // New notifications for the same (endpoint, cluster) shall - // simply overrride the old ones - if (path.cluster == cluster && path.endpoint == endpoint) - { - path.context = context; - return; - } - } - if (mNumPendingNotifications < kMaxPendingNotifications) - { - mPendingNotifications[mNumPendingNotifications++] = { context, cluster, endpoint }; - } - else - { - mPendingNotifications[mNextToOverride] = { context, cluster, endpoint }; - mNextToOverride++; - mNextToOverride %= kMaxPendingNotifications; - } - } - - private: - System::Clock::Timestamp mLastUpdateTime; - // TODO: Make the pending notifications list of binding table indecies and list of contexts - ClusterPath mPendingNotifications[kMaxPendingNotifications]; - - NodeId mNodeId; - uint8_t mNumPendingNotifications = 0; - uint8_t mNextToOverride = 0; - FabricIndex mFabricIndex; - }; - - // The pool for all the pending comands. - class PendingNotificationMap - { - public: - PendingNotificationEntry * FindLRUEntry(); - - PendingNotificationEntry * FindEntry(FabricIndex fabricIndex, NodeId node); - - CHIP_ERROR AddPendingNotification(FabricIndex fabricIndex, NodeId node, EndpointId endpoint, ClusterId cluster, - void * context); - - void RemoveEntry(PendingNotificationEntry * entry) { mPendingNotificationMap.ReleaseObject(entry); } - - template - Loop ForEachActiveObject(Function && function) - { - return mPendingNotificationMap.ForEachActiveObject(std::forward(function)); - } - - private: - ObjectPool mPendingNotificationMap; - }; - static void HandleDeviceConnected(void * context, OperationalDeviceProxy * device); void HandleDeviceConnected(OperationalDeviceProxy * device); @@ -205,9 +106,6 @@ class BindingManager CHIP_ERROR EstablishConnection(FabricIndex fabric, NodeId node); - // Called when CASE session is established to a peer device. Will send all the pending commands to the peer. - void SyncPendingNotificationsToPeer(OperationalDeviceProxy * device, PendingNotificationEntry * pendingClusters); - PendingNotificationMap mPendingNotificationMap; BoundDeviceChangedHandler mBoundDeviceChangedHandler; Server * mAppServer = nullptr; diff --git a/src/app/clusters/bindings/PendingNotificationMap.cpp b/src/app/clusters/bindings/PendingNotificationMap.cpp new file mode 100644 index 00000000000000..49b48eb420c565 --- /dev/null +++ b/src/app/clusters/bindings/PendingNotificationMap.cpp @@ -0,0 +1,152 @@ +/* + * + * 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. + */ + +#include + +#include +#include + +namespace chip { + +CHIP_ERROR PendingNotificationMap::FindLRUConnectPeer(FabricIndex * fabric, NodeId * node) +{ + // When entries are added to PendingNotificationMap, they are appended to the end. + // To find the LRU peer, we need to find the peer whose last entry in the map is closer + // to the start of the list than the last entry of any other peer. + + // First, set up a way to easily track which entries correspond to the same peer. + uint8_t bindingWithSamePeer[EMBER_BINDING_TABLE_SIZE]; + + for (uint8_t i = 0; i < EMBER_BINDING_TABLE_SIZE; i++) + { + EmberBindingTableEntry entry; + emberGetBinding(i, &entry); + if (entry.type != EMBER_UNICAST_BINDING) + { + continue; + } + bool foundSamePeer = false; + for (uint8_t j = 0; j < i; j++) + { + EmberBindingTableEntry checkEntry; + emberGetBinding(j, &checkEntry); + if (checkEntry.type == EMBER_UNICAST_BINDING && checkEntry.fabricIndex == entry.fabricIndex && + checkEntry.nodeId == entry.nodeId) + { + foundSamePeer = true; + bindingWithSamePeer[i] = j; + break; + } + } + if (!foundSamePeer) + { + bindingWithSamePeer[i] = i; + } + } + + uint16_t lastAppear[EMBER_BINDING_TABLE_SIZE]; + for (uint16_t & value : lastAppear) + { + value = UINT16_MAX; + } + uint16_t appearIndex = 0; + for (PendingNotificationEntry pendingNotification : *this) + { + lastAppear[bindingWithSamePeer[pendingNotification.mBindingEntryId]] = appearIndex; + appearIndex++; + } + uint8_t lruBindingEntryIndex; + uint16_t minLastAppearValue = UINT16_MAX; + for (uint8_t i = 0; i < EMBER_BINDING_TABLE_SIZE; i++) + { + if (lastAppear[i] < minLastAppearValue) + { + lruBindingEntryIndex = i; + minLastAppearValue = lastAppear[i]; + } + } + if (minLastAppearValue < UINT16_MAX) + { + EmberBindingTableEntry entry; + emberGetBinding(lruBindingEntryIndex, &entry); + *fabric = entry.fabricIndex; + *node = entry.nodeId; + return CHIP_NO_ERROR; + } + return CHIP_ERROR_NOT_FOUND; +} + +void PendingNotificationMap::AddPendingNotification(uint8_t bindingEntryId, void * context) +{ + RemoveEntry(bindingEntryId); + mPendingBindingEntries[mNumEntries] = bindingEntryId; + mPendingContexts[mNumEntries] = context; + mNumEntries++; +} + +void PendingNotificationMap::RemoveEntry(uint8_t bindingEntryId) +{ + uint8_t newEntryCount = 0; + for (int i = 0; i < mNumEntries; i++) + { + if (mPendingBindingEntries[i] != bindingEntryId) + { + mPendingBindingEntries[newEntryCount] = mPendingBindingEntries[i]; + mPendingContexts[newEntryCount] = mPendingContexts[i]; + newEntryCount++; + } + } + mNumEntries = newEntryCount; +} + +void PendingNotificationMap::RemoveAllEntriesForNode(FabricIndex fabric, NodeId node) +{ + uint8_t newEntryCount = 0; + for (int i = 0; i < mNumEntries; i++) + { + EmberBindingTableEntry entry; + emberGetBinding(mPendingBindingEntries[i], &entry); + + if (entry.fabricIndex != fabric || entry.nodeId != node) + { + mPendingBindingEntries[newEntryCount] = mPendingBindingEntries[i]; + mPendingContexts[newEntryCount] = mPendingContexts[i]; + newEntryCount++; + } + } + mNumEntries = newEntryCount; +} + +void PendingNotificationMap::RemoveAllEntriesForFabric(FabricIndex fabric) +{ + uint8_t newEntryCount = 0; + for (int i = 0; i < mNumEntries; i++) + { + EmberBindingTableEntry entry; + emberGetBinding(mPendingBindingEntries[i], &entry); + + if (entry.fabricIndex != fabric) + { + mPendingBindingEntries[newEntryCount] = mPendingBindingEntries[i]; + mPendingContexts[newEntryCount] = mPendingContexts[i]; + newEntryCount++; + } + } + mNumEntries = newEntryCount; +} + +} // namespace chip diff --git a/src/app/clusters/bindings/PendingNotificationMap.h b/src/app/clusters/bindings/PendingNotificationMap.h new file mode 100644 index 00000000000000..8a9559cac9cefa --- /dev/null +++ b/src/app/clusters/bindings/PendingNotificationMap.h @@ -0,0 +1,85 @@ +/* + * + * 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. + */ + +#include +#include +#include + +namespace chip { + +struct PendingNotificationEntry +{ +public: + uint8_t mBindingEntryId; + void * mContext; +}; + +// The pool for all the pending comands. +class PendingNotificationMap +{ +public: + static constexpr uint8_t kMaxPendingNotifications = EMBER_BINDING_TABLE_SIZE; + + friend class Iterator; + + class Iterator + { + public: + Iterator(PendingNotificationMap * map, int16_t index) : mMap(map), mIndex(index) {} + + PendingNotificationEntry operator*() + { + return PendingNotificationEntry{ mMap->mPendingBindingEntries[mIndex], mMap->mPendingContexts[mIndex] }; + } + + Iterator operator++() + { + mIndex++; + return *this; + } + + bool operator!=(const Iterator & rhs) { return mIndex != rhs.mIndex; } + + private: + PendingNotificationMap * mMap; + int16_t mIndex; + }; + + Iterator begin() { return Iterator(this, 0); } + + Iterator end() { return Iterator(this, mNumEntries); } + + CHIP_ERROR FindLRUConnectPeer(FabricIndex * fabric, NodeId * node); + + void AddPendingNotification(uint8_t bindingEntryId, void * context); + + void RemoveEntry(uint8_t bindingEntryId); + + void RemoveAllEntriesForNode(FabricTable * fabricTable, PeerId peer); + + void RemoveAllEntriesForNode(FabricIndex fabric, NodeId node); + + void RemoveAllEntriesForFabric(FabricIndex fabric); + +private: + uint8_t mPendingBindingEntries[kMaxPendingNotifications]; + void * mPendingContexts[kMaxPendingNotifications]; + + uint8_t mNumEntries = 0; +}; + +} // namespace chip diff --git a/src/app/clusters/bindings/bindings.cpp b/src/app/clusters/bindings/bindings.cpp index 13bfc15d7ebb8c..cfe7ea5f81e773 100644 --- a/src/app/clusters/bindings/bindings.cpp +++ b/src/app/clusters/bindings/bindings.cpp @@ -108,9 +108,10 @@ bool emberAfBindingClusterBindCallback(app::CommandHandler * commandObj, const a return true; } + emberSetBinding(bindingIndex, &bindingEntry); if (nodeId) { - CHIP_ERROR err = BindingManager::GetInstance().UnicastBindingCreated(fabricIndex, nodeId); + CHIP_ERROR err = BindingManager::GetInstance().UnicastBindingCreated(bindingEntry); if (err != CHIP_NO_ERROR) { ChipLogProgress( @@ -118,26 +119,11 @@ bool emberAfBindingClusterBindCallback(app::CommandHandler * commandObj, const a ChipLogValueX64(nodeId), err.Format()); } } - emberSetBinding(bindingIndex, &bindingEntry); + emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS); return true; } -static uint8_t GetNumberOfUnicastBindingForNode(FabricIndex fabric, NodeId node) -{ - uint8_t numBinding = 0; - EmberBindingTableEntry entry; - for (uint8_t i = 0; i < EMBER_BINDING_TABLE_SIZE; i++) - { - if (emberGetBinding(i, &entry) == EMBER_SUCCESS && entry.type == EMBER_UNICAST_BINDING && entry.fabricIndex == fabric && - entry.nodeId == node) - { - numBinding++; - } - } - return numBinding; -} - bool emberAfBindingClusterUnbindCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, const Commands::Unbind::DecodableType & commandData) { @@ -173,17 +159,14 @@ bool emberAfBindingClusterUnbindCallback(app::CommandHandler * commandObj, const return true; } - emberDeleteBinding(bindingIndex); - if (nodeId != 0 && GetNumberOfUnicastBindingForNode(fabricIndex, nodeId) == 0) + CHIP_ERROR err = BindingManager::GetInstance().UnicastBindingRemoved(bindingIndex); + if (err != CHIP_NO_ERROR) { - CHIP_ERROR err = BindingManager::GetInstance().LastUnicastBindingRemoved(fabricIndex, nodeId); - if (err != CHIP_NO_ERROR) - { - ChipLogError(Zcl, "Binding: Failed to disconnect device " ChipLogFormatX64 ": %s", ChipLogValueX64(nodeId), - err.AsString()); - } + ChipLogError(Zcl, "Binding: Failed to remove pending notification for unicast binding" ChipLogFormatX64 ": %s", + ChipLogValueX64(nodeId), err.AsString()); } + emberDeleteBinding(bindingIndex); emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS); return true; } diff --git a/src/app/util/binding-table.h b/src/app/util/binding-table.h index 7188830b3d2803..6b0abe2f957f34 100644 --- a/src/app/util/binding-table.h +++ b/src/app/util/binding-table.h @@ -23,9 +23,6 @@ #include -// Should this be configurable by the app somehow? -#define BINDING_TABLE_SIZE 10 - EmberStatus emberGetBinding(uint8_t index, EmberBindingTableEntry * result); EmberStatus emberSetBinding(uint8_t index, EmberBindingTableEntry * result);