| /** |
| * Copyright (c) 2024 Project CHIP Authors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include <app/AttributeAccessInterfaceRegistry.h> |
| |
| #include <app/AttributeAccessInterfaceCache.h> |
| |
| using namespace chip::app; |
| |
| namespace { |
| |
| AttributeAccessInterface * gAttributeAccessOverrides = nullptr; |
| AttributeAccessInterfaceCache gAttributeAccessInterfaceCache; |
| |
| // shouldUnregister returns true if the given AttributeAccessInterface should be |
| // unregistered. |
| template <typename F> |
| void UnregisterMatchingAttributeAccessInterfaces(F shouldUnregister) |
| { |
| AttributeAccessInterface * prev = nullptr; |
| AttributeAccessInterface * cur = gAttributeAccessOverrides; |
| while (cur) |
| { |
| AttributeAccessInterface * next = cur->GetNext(); |
| if (shouldUnregister(cur)) |
| { |
| // Remove it from the list |
| if (prev) |
| { |
| prev->SetNext(next); |
| } |
| else |
| { |
| gAttributeAccessOverrides = next; |
| } |
| |
| cur->SetNext(nullptr); |
| |
| // Do not change prev in this case. |
| } |
| else |
| { |
| prev = cur; |
| } |
| cur = next; |
| } |
| } |
| |
| } // namespace |
| |
| void unregisterAttributeAccessOverride(AttributeAccessInterface * attrOverride) |
| { |
| gAttributeAccessInterfaceCache.Invalidate(); |
| UnregisterMatchingAttributeAccessInterfaces([attrOverride](AttributeAccessInterface * entry) { return entry == attrOverride; }); |
| } |
| |
| void unregisterAllAttributeAccessOverridesForEndpoint(EmberAfDefinedEndpoint * definedEndpoint) |
| { |
| UnregisterMatchingAttributeAccessInterfaces( |
| [endpoint = definedEndpoint->endpoint](AttributeAccessInterface * entry) { return entry->MatchesEndpoint(endpoint); }); |
| } |
| |
| bool registerAttributeAccessOverride(AttributeAccessInterface * attrOverride) |
| { |
| gAttributeAccessInterfaceCache.Invalidate(); |
| for (auto * cur = gAttributeAccessOverrides; cur; cur = cur->GetNext()) |
| { |
| if (cur->Matches(*attrOverride)) |
| { |
| ChipLogError(InteractionModel, "Duplicate attribute override registration failed"); |
| return false; |
| } |
| } |
| attrOverride->SetNext(gAttributeAccessOverrides); |
| gAttributeAccessOverrides = attrOverride; |
| return true; |
| } |
| |
| namespace chip { |
| namespace app { |
| |
| app::AttributeAccessInterface * GetAttributeAccessOverride(EndpointId endpointId, ClusterId clusterId) |
| { |
| using CacheResult = AttributeAccessInterfaceCache::CacheResult; |
| |
| AttributeAccessInterface * cached = nullptr; |
| CacheResult result = gAttributeAccessInterfaceCache.Get(endpointId, clusterId, &cached); |
| switch (result) |
| { |
| case CacheResult::kDefinitelyUnused: |
| return nullptr; |
| case CacheResult::kDefinitelyUsed: |
| return cached; |
| case CacheResult::kCacheMiss: |
| default: |
| // Did not cache yet, search set of AAI registered, and cache if found. |
| for (app::AttributeAccessInterface * cur = gAttributeAccessOverrides; cur; cur = cur->GetNext()) |
| { |
| if (cur->Matches(endpointId, clusterId)) |
| { |
| gAttributeAccessInterfaceCache.MarkUsed(endpointId, clusterId, cur); |
| return cur; |
| } |
| } |
| |
| // Did not find AAI registered: mark as definitely not using. |
| gAttributeAccessInterfaceCache.MarkUnused(endpointId, clusterId); |
| } |
| |
| return nullptr; |
| } |
| |
| } // namespace app |
| } // namespace chip |