| /* |
| * |
| * Copyright (c) 2021 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. |
| */ |
| |
| #pragma once |
| |
| #include "lib/core/CHIPError.h" |
| #include "system/SystemPacketBuffer.h" |
| #include "system/TLVPacketBufferBackingStore.h" |
| #include <app/AppConfig.h> |
| #include <app/AttributePathParams.h> |
| #include <app/BufferedReadCallback.h> |
| #include <app/ReadClient.h> |
| #include <app/data-model/DecodableList.h> |
| #include <app/data-model/Decode.h> |
| #include <lib/support/Variant.h> |
| #include <list> |
| #include <map> |
| #include <queue> |
| #include <set> |
| #include <vector> |
| |
| #if CHIP_CONFIG_ENABLE_READ_CLIENT |
| namespace chip { |
| namespace app { |
| /* |
| * This implements a cluster state cache designed to aggregate both attribute and event data received by a client |
| * from either read or subscribe interactions and keep it resident and available for clients to |
| * query at any time while the cache is active. |
| * |
| * The cache can be used with either read/subscribe, with the consumer connecting it up appropriately |
| * to the right ReadClient instance. |
| * |
| * The cache provides an up-to-date and consistent view of the state of a target node, with the scope of the |
| * state being determined by the associated ReadClient's path set. |
| * |
| * The cache provides a number of getters and helper functions to iterate over the topology |
| * of the received data which is organized by endpoint, cluster and attribute ID (for attributes). These permit greater |
| * flexibility when dealing with interactions that use wildcards heavily. |
| * |
| * For events, functions that permit iteration over the cached events sorted by event number are provided. |
| * |
| * The data is stored internally in the cache as TLV. This permits re-use of the existing cluster objects |
| * to de-serialize the state on-demand. |
| * |
| * The cache serves as a callback adapter as well in that it 'forwards' the ReadClient::Callback calls transparently |
| * through to a registered callback. In addition, it provides its own enhancements to the base ReadClient::Callback |
| * to make it easier to know what has changed in the cache. |
| * |
| * **NOTE** |
| * 1. This already includes the BufferedReadCallback, so there is no need to add that to the ReadClient callback chain. |
| * 2. The same cache cannot be used by multiple subscribe/read interactions at the same time. |
| * |
| */ |
| template <bool CanEnableDataCaching> |
| class ClusterStateCacheT : protected ReadClient::Callback |
| { |
| public: |
| class Callback : public ReadClient::Callback |
| { |
| public: |
| Callback() = default; |
| |
| // Callbacks are not expected to be copyable or movable. |
| Callback(const Callback &) = delete; |
| Callback(Callback &&) = delete; |
| Callback & operator=(const Callback &) = delete; |
| Callback & operator=(Callback &&) = delete; |
| |
| /* |
| * Called anytime an attribute value has changed in the cache |
| */ |
| virtual void OnAttributeChanged(ClusterStateCacheT * cache, const ConcreteAttributePath & path){}; |
| |
| /* |
| * Called anytime any attribute in a cluster has changed in the cache |
| */ |
| virtual void OnClusterChanged(ClusterStateCacheT * cache, EndpointId endpointId, ClusterId clusterId){}; |
| |
| /* |
| * Called anytime an endpoint was added to the cache |
| */ |
| virtual void OnEndpointAdded(ClusterStateCacheT * cache, EndpointId endpointId){}; |
| }; |
| |
| /** |
| * |
| * @param [in] callback the derived callback which inherit from ReadClient::Callback |
| * @param [in] highestReceivedEventNumber optional highest received event number, if cache receive the events with the number |
| * less than or equal to this value, skip those events |
| */ |
| ClusterStateCacheT(Callback & callback, Optional<EventNumber> highestReceivedEventNumber = Optional<EventNumber>::Missing()) : |
| mCallback(callback), mBufferedReader(*this) |
| { |
| mHighestReceivedEventNumber = highestReceivedEventNumber; |
| } |
| |
| template <bool DataCachingEnabled = CanEnableDataCaching, std::enable_if_t<DataCachingEnabled, bool> = true> |
| ClusterStateCacheT(Callback & callback, Optional<EventNumber> highestReceivedEventNumber = Optional<EventNumber>::Missing(), |
| bool cacheData = true) : |
| mCallback(callback), |
| mBufferedReader(*this), mCacheData(cacheData) |
| { |
| mHighestReceivedEventNumber = highestReceivedEventNumber; |
| } |
| |
| ClusterStateCacheT(const ClusterStateCacheT &) = delete; |
| ClusterStateCacheT(ClusterStateCacheT &&) = delete; |
| ClusterStateCacheT & operator=(const ClusterStateCacheT &) = delete; |
| ClusterStateCacheT & operator=(ClusterStateCacheT &&) = delete; |
| |
| void SetHighestReceivedEventNumber(EventNumber highestReceivedEventNumber) |
| { |
| mHighestReceivedEventNumber.SetValue(highestReceivedEventNumber); |
| } |
| |
| /* |
| * When registering as a callback to the ReadClient, the ClusterStateCache cannot not be passed as a callback |
| * directly. Instead, utilize this method below to correctly set up the callback chain such that |
| * the buffered reader is the first callback in the chain before calling into cache subsequently. |
| */ |
| ReadClient::Callback & GetBufferedCallback() { return mBufferedReader; } |
| |
| /* |
| * Retrieve the value of an attribute from the cache (if present) given a concrete path by decoding |
| * it using DataModel::Decode into the in-out argument 'value'. |
| * |
| * For some types of attributes, the value for the attribute is directly backed by the underlying TLV buffer |
| * and has pointers into that buffer. (e.g octet strings, char strings and lists). This buffer only remains |
| * valid until the cached value for that path is updated, so it must not be held |
| * across any async call boundaries. |
| * |
| * The template parameter AttributeObjectTypeT is generally expected to be a |
| * ClusterName::Attributes::AttributeName::DecodableType, but any |
| * object that can be decoded using the DataModel::Decode machinery will work. |
| * |
| * Notable return values: |
| * - If the provided attribute object's Cluster and Attribute IDs don't match that of the provided path, |
| * a CHIP_ERROR_SCHEMA_MISMATCH shall be returned. |
| * |
| * - If neither data or status for the specified path don't exist in the cache, CHIP_ERROR_KEY_NOT_FOUND |
| * shall be returned. |
| * |
| * - If a StatusIB is present in the cache instead of data, a CHIP_ERROR_IM_STATUS_CODE_RECEIVED error |
| * shall be returned from this call instead. The actual StatusIB can be retrieved using the GetStatus() API below. |
| * |
| */ |
| template <typename AttributeObjectTypeT> |
| CHIP_ERROR Get(const ConcreteAttributePath & path, typename AttributeObjectTypeT::DecodableType & value) const |
| { |
| TLV::TLVReader reader; |
| |
| if (path.mClusterId != AttributeObjectTypeT::GetClusterId() || path.mAttributeId != AttributeObjectTypeT::GetAttributeId()) |
| { |
| return CHIP_ERROR_SCHEMA_MISMATCH; |
| } |
| |
| ReturnErrorOnFailure(Get(path, reader)); |
| return DataModel::Decode(reader, value); |
| } |
| |
| /** |
| * Get the value of a particular attribute for the given endpoint. See the |
| * documentation for Get() with a ConcreteAttributePath above. |
| */ |
| template <typename AttributeObjectTypeT> |
| CHIP_ERROR Get(EndpointId endpoint, typename AttributeObjectTypeT::DecodableType & value) const |
| { |
| ConcreteAttributePath path(endpoint, AttributeObjectTypeT::GetClusterId(), AttributeObjectTypeT::GetAttributeId()); |
| return Get<AttributeObjectTypeT>(path, value); |
| } |
| |
| /* |
| * Retrieve the StatusIB for a given attribute if one exists currently in the cache. |
| * |
| * Notable return values: |
| * - If neither data or status for the specified path don't exist in the cache, CHIP_ERROR_KEY_NOT_FOUND |
| * shall be returned. |
| * |
| * - If data exists in the cache instead of status, CHIP_ERROR_INVALID_ARGUMENT shall be returned. |
| * |
| */ |
| CHIP_ERROR GetStatus(const ConcreteAttributePath & path, StatusIB & status) const; |
| |
| /* |
| * Encapsulates a StatusIB and a ConcreteAttributePath pair. |
| */ |
| struct AttributeStatus |
| { |
| AttributeStatus(const ConcreteAttributePath & path, StatusIB & status) : mPath(path), mStatus(status) {} |
| ConcreteAttributePath mPath; |
| StatusIB mStatus; |
| }; |
| |
| /* |
| * Retrieve the value of an entire cluster instance from the cache (if present) given a path |
| * and decode it using DataModel::Decode into the in-out argument 'value'. If any StatusIBs |
| * are present in the cache instead of data, they will be provided in the statusList argument. |
| * |
| * For some types of attributes, the value for the attribute is directly backed by the underlying TLV buffer |
| * and has pointers into that buffer. (e.g octet strings, char strings and lists). This buffer only remains |
| * valid until the cached value for that path is updated, so it must not be held |
| * across any async call boundaries. |
| * |
| * The template parameter ClusterObjectT is generally expected to be a |
| * ClusterName::Attributes::DecodableType, but any |
| * object that can be decoded using the DataModel::Decode machinery will work. |
| * |
| * Notable return values: |
| * - If neither data or status for the specified path exist in the cache, CHIP_ERROR_KEY_NOT_FOUND |
| * shall be returned. |
| * |
| */ |
| template <typename ClusterObjectTypeT> |
| CHIP_ERROR Get(EndpointId endpointId, ClusterId clusterId, ClusterObjectTypeT & value, |
| std::list<AttributeStatus> & statusList) const |
| { |
| statusList.clear(); |
| |
| return ForEachAttribute(endpointId, clusterId, [&value, this, &statusList](const ConcreteAttributePath & path) { |
| TLV::TLVReader reader; |
| CHIP_ERROR err; |
| |
| err = Get(path, reader); |
| if (err == CHIP_ERROR_IM_STATUS_CODE_RECEIVED) |
| { |
| StatusIB status; |
| ReturnErrorOnFailure(GetStatus(path, status)); |
| statusList.push_back(AttributeStatus(path, status)); |
| err = CHIP_NO_ERROR; |
| } |
| else if (err == CHIP_NO_ERROR) |
| { |
| ReturnErrorOnFailure(DataModel::Decode(reader, path, value)); |
| } |
| else |
| { |
| return err; |
| } |
| |
| return CHIP_NO_ERROR; |
| }); |
| } |
| |
| /* |
| * Retrieve the value of an attribute by updating a in-out TLVReader to be positioned |
| * right at the attribute value. |
| * |
| * The underlying TLV buffer only remains valid until the cached value for that path is updated, so it must |
| * not be held across any async call boundaries. |
| * |
| * Notable return values: |
| * - If neither data nor status for the specified path exist in the cache, CHIP_ERROR_KEY_NOT_FOUND |
| * shall be returned. |
| * |
| * - If a StatusIB is present in the cache instead of data, a CHIP_ERROR_IM_STATUS_CODE_RECEIVED error |
| * shall be returned from this call instead. The actual StatusIB can be retrieved using the GetStatus() API above. |
| * |
| */ |
| CHIP_ERROR Get(const ConcreteAttributePath & path, TLV::TLVReader & reader) const; |
| |
| /* |
| * Retrieve the data version for the given cluster. If there is no data for the specified path in the cache, |
| * CHIP_ERROR_KEY_NOT_FOUND shall be returned. Otherwise aVersion will be set to the |
| * current data version for the cluster (which may have no value if we don't have a known data version |
| * for it, for example because none of our paths were wildcards that covered the whole cluster). |
| */ |
| CHIP_ERROR GetVersion(const ConcreteClusterPath & path, Optional<DataVersion> & aVersion) const; |
| |
| /* |
| * Get highest received event number. |
| */ |
| virtual CHIP_ERROR GetHighestReceivedEventNumber(Optional<EventNumber> & aEventNumber) final |
| { |
| aEventNumber = mHighestReceivedEventNumber; |
| return CHIP_NO_ERROR; |
| } |
| |
| /* |
| * Retrieve the value of an event from the cache given an EventNumber by decoding |
| * it using DataModel::Decode into the in-out argument 'value'. |
| * |
| * This should be used in conjunction with the ForEachEvent() iterator function to |
| * retrieve the EventHeader (and corresponding metadata information for the event) along with its EventNumber. |
| * |
| * For some types of events, the values for the fields in the event are directly backed by the underlying TLV buffer |
| * and have pointers into that buffer. (e.g octet strings, char strings and lists). Unlike its attribute counterpart, |
| * these pointers are stable and will not change until a call to `ClearEventCache` happens. |
| * |
| * The template parameter EventObjectTypeT is generally expected to be a |
| * ClusterName::Events::EventName::DecodableType, but any |
| * object that can be decoded using the DataModel::Decode machinery will work. |
| * |
| * Notable return values: |
| * - If the provided event object's Cluster and Event IDs don't match those of the event in the cache, |
| * a CHIP_ERROR_SCHEMA_MISMATCH shall be returned. |
| * |
| * - If event doesn't exist in the cache, CHIP_ERROR_KEY_NOT_FOUND |
| * shall be returned. |
| */ |
| |
| template <typename EventObjectTypeT> |
| CHIP_ERROR Get(EventNumber eventNumber, EventObjectTypeT & value) const |
| { |
| TLV::TLVReader reader; |
| CHIP_ERROR err; |
| |
| auto * eventData = GetEventData(eventNumber, err); |
| ReturnErrorOnFailure(err); |
| |
| if (eventData->first.mPath.mClusterId != value.GetClusterId() || eventData->first.mPath.mEventId != value.GetEventId()) |
| { |
| return CHIP_ERROR_SCHEMA_MISMATCH; |
| } |
| |
| ReturnErrorOnFailure(Get(eventNumber, reader)); |
| return DataModel::Decode(reader, value); |
| } |
| |
| /* |
| * Retrieve the data of an event by updating a in-out TLVReader to be positioned |
| * right at the structure that encapsulates the event payload. |
| * |
| * Notable return values: |
| * - If no event with a matching eventNumber exists in the cache, CHIP_ERROR_KEY_NOT_FOUND |
| * shall be returned. |
| * |
| */ |
| CHIP_ERROR Get(EventNumber eventNumber, TLV::TLVReader & reader) const; |
| |
| /* |
| * Retrieve the StatusIB for a specific event from the event status cache (if one exists). |
| * Otherwise, a CHIP_ERROR_KEY_NOT_FOUND error will be returned. |
| * |
| * This is to be used with the `ForEachEventStatus` iterator function. |
| * |
| * NOTE: Receipt of a StatusIB does not affect any pre-existing or future event data entries in the cache (and vice-versa). |
| * |
| */ |
| CHIP_ERROR GetStatus(const ConcreteEventPath & path, StatusIB & status) const; |
| |
| /* |
| * Execute an iterator function that is called for every attribute |
| * in a given endpoint and cluster. The function when invoked is provided a concrete attribute path |
| * to every attribute that matches in the cache. |
| * |
| * The iterator is expected to have this signature: |
| * CHIP_ERROR IteratorFunc(const ConcreteAttributePath &path); |
| * |
| * Notable return values: |
| * - If a cluster instance corresponding to endpointId and clusterId doesn't exist in the cache, |
| * CHIP_ERROR_KEY_NOT_FOUND shall be returned. |
| * |
| * - If func returns an error, that will result in termination of any further iteration over attributes |
| * and that error shall be returned back up to the original call to this function. |
| * |
| */ |
| template <typename IteratorFunc> |
| CHIP_ERROR ForEachAttribute(EndpointId endpointId, ClusterId clusterId, IteratorFunc func) const |
| { |
| CHIP_ERROR err; |
| |
| auto clusterState = GetClusterState(endpointId, clusterId, err); |
| ReturnErrorOnFailure(err); |
| |
| for (auto & attributeIter : clusterState->mAttributes) |
| { |
| const ConcreteAttributePath path(endpointId, clusterId, attributeIter.first); |
| ReturnErrorOnFailure(func(path)); |
| } |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| /* |
| * Execute an iterator function that is called for every attribute |
| * for a given cluster across all endpoints in the cache. The function is passed a |
| * concrete attribute path to every attribute that matches in the cache. |
| * |
| * The iterator is expected to have this signature: |
| * CHIP_ERROR IteratorFunc(const ConcreteAttributePath &path); |
| * |
| * Notable return values: |
| * - If func returns an error, that will result in termination of any further iteration over attributes |
| * and that error shall be returned back up to the original call to this function. |
| * |
| */ |
| template <typename IteratorFunc> |
| CHIP_ERROR ForEachAttribute(ClusterId clusterId, IteratorFunc func) const |
| { |
| for (auto & endpointIter : mCache) |
| { |
| for (auto & clusterIter : endpointIter.second) |
| { |
| if (clusterIter.first == clusterId) |
| { |
| for (auto & attributeIter : clusterIter.second.mAttributes) |
| { |
| const ConcreteAttributePath path(endpointIter.first, clusterId, attributeIter.first); |
| ReturnErrorOnFailure(func(path)); |
| } |
| } |
| } |
| } |
| return CHIP_NO_ERROR; |
| } |
| |
| /* |
| * Execute an iterator function that is called for every cluster |
| * in a given endpoint and passed a ClusterId for every cluster that |
| * matches. |
| * |
| * The iterator is expected to have this signature: |
| * CHIP_ERROR IteratorFunc(ClusterId clusterId); |
| * |
| * Notable return values: |
| * - If func returns an error, that will result in termination of any further iteration over attributes |
| * and that error shall be returned back up to the original call to this function. |
| * |
| */ |
| template <typename IteratorFunc> |
| CHIP_ERROR ForEachCluster(EndpointId endpointId, IteratorFunc func) const |
| { |
| auto endpointIter = mCache.find(endpointId); |
| if (endpointIter->first == endpointId) |
| { |
| for (auto & clusterIter : endpointIter->second) |
| { |
| ReturnErrorOnFailure(func(clusterIter.first)); |
| } |
| } |
| return CHIP_NO_ERROR; |
| } |
| |
| /* |
| * Execute an iterator function that is called for every event in the event data cache that satisfies the following |
| * conditions: |
| * - It matches the provided path filter |
| * - Its event number is greater than or equal to the provided minimum event number filter. |
| * |
| * Each filter argument can be omitted from the match criteria above by passing in an empty EventPathParams() and/or |
| * a minimum event filter of 0. |
| * |
| * This iterator is called in increasing order from the event with the lowest event number to the highest. |
| * |
| * The function is passed a const reference to the EventHeader associated with that event. |
| * |
| * The iterator is expected to have this signature: |
| * CHIP_ERROR IteratorFunc(const EventHeader & eventHeader); |
| * |
| * Notable return values: |
| * - If func returns an error, that will result in termination of any further iteration over events |
| * and that error shall be returned back up to the original call to this function. |
| * |
| */ |
| template <typename IteratorFunc> |
| CHIP_ERROR ForEachEventData(IteratorFunc func, EventPathParams pathFilter = EventPathParams(), |
| EventNumber minEventNumberFilter = 0) const |
| { |
| for (const auto & item : mEventDataCache) |
| { |
| if (pathFilter.IsEventPathSupersetOf(item.first.mPath) && item.first.mEventNumber >= minEventNumberFilter) |
| { |
| ReturnErrorOnFailure(func(item.first)); |
| } |
| } |
| |
| return CHIP_NO_ERROR; |
| } |
| |
| /* |
| * Execute an iterator function that is called for every StatusIB in the event status cache. |
| * |
| * The iterator is expected to have this signature: |
| * CHIP_ERROR IteratorFunc(const ConcreteEventPath & eventPath, const StatusIB & statusIB); |
| * |
| * Notable return values: |
| * - If func returns an error, that will result in termination of any further iteration over events |
| * and that error shall be returned back up to the original call to this function. |
| * |
| * NOTE: Receipt of a StatusIB does not affect any pre-existing event data entries in the cache (and vice-versa). |
| * |
| */ |
| template <typename IteratorFunc> |
| CHIP_ERROR ForEachEventStatus(IteratorFunc func) const |
| { |
| for (const auto & item : mEventStatusCache) |
| { |
| ReturnErrorOnFailure(func(item.first, item.second)); |
| } |
| } |
| |
| /* |
| * Clear out all the attribute data and DataVersions stored for a given endpoint. |
| */ |
| void ClearAttributes(EndpointId endpoint); |
| |
| /* |
| * Clear out all the attribute data and the DataVersion stored for a given cluster. |
| */ |
| void ClearAttributes(const ConcreteClusterPath & cluster); |
| |
| /* |
| * Clear out the data (or size, if not storing data) stored for an |
| * attribute. |
| */ |
| void ClearAttribute(const ConcreteAttributePath & attribute); |
| |
| /* |
| * Clear out the event data and status caches. |
| * |
| * By default, this will not clear out any internally tracked event counters, specifically: |
| * - the highest event number seen so far. This is used in reads/subscribe requests to express to the receiving |
| * server to not send events that the client has already seen so far. |
| * |
| * That can be over-ridden by passing in 'true' to `resetTrackedEventCounters`. |
| * |
| */ |
| void ClearEventCache(bool resetTrackedEventCounters = false) |
| { |
| mEventDataCache.clear(); |
| if (resetTrackedEventCounters) |
| { |
| mHighestReceivedEventNumber.ClearValue(); |
| } |
| |
| mEventStatusCache.clear(); |
| } |
| |
| /* |
| * Get the last concrete report data path, if path is not concrete cluster path, return CHIP_ERROR_NOT_FOUND |
| * |
| */ |
| CHIP_ERROR GetLastReportDataPath(ConcreteClusterPath & aPath); |
| |
| private: |
| // An attribute state can be one of three things: |
| // * If we got a path-specific error for the attribute, the corresponding |
| // status. |
| // * If we got data for the attribute and we are storing data ourselves, the |
| // data. |
| // * If we got data for the attribute and we are not storing data |
| // oureselves, the size of the data, so we can still prioritize sending |
| // DataVersions correctly. |
| // |
| // The data for a single attribute is not going to be gigabytes in size, so |
| // using uint32_t for the size is fine; on 64-bit systems this can save |
| // quite a bit of space. |
| using AttributeData = Platform::ScopedMemoryBufferWithSize<uint8_t>; |
| using AttributeState = std::conditional_t<CanEnableDataCaching, Variant<StatusIB, AttributeData, uint32_t>, uint32_t>; |
| // mPendingDataVersion represents a tentative data version for a cluster that we have gotten some reports for. |
| // |
| // mCurrentDataVersion represents a known data version for a cluster. In order for this to have a |
| // value the cluster must be included in a path in mRequestPathSet that has a wildcard attribute |
| // and we must not be in the middle of receiving reports for that cluster. |
| struct ClusterState |
| { |
| std::map<AttributeId, AttributeState> mAttributes; |
| Optional<DataVersion> mPendingDataVersion; |
| Optional<DataVersion> mCommittedDataVersion; |
| }; |
| using EndpointState = std::map<ClusterId, ClusterState>; |
| using NodeState = std::map<EndpointId, EndpointState>; |
| |
| struct Comparator |
| { |
| bool operator()(const AttributePathParams & x, const AttributePathParams & y) const |
| { |
| return x.mEndpointId < y.mEndpointId || x.mClusterId < y.mClusterId; |
| } |
| }; |
| |
| using EventData = std::pair<EventHeader, System::PacketBufferHandle>; |
| |
| // |
| // This is a custom comparator for use with the std::set<EventData> below. Uniqueness |
| // is determined solely by the event number associated with each event. |
| // |
| struct EventDataCompare |
| { |
| bool operator()(const EventData & lhs, const EventData & rhs) const |
| { |
| return (lhs.first.mEventNumber < rhs.first.mEventNumber); |
| } |
| }; |
| |
| /* |
| * These functions provide a way to index into the cached state with different sub-sets of a path, returning |
| * appropriate slices of the data as requested. |
| * |
| * In all variants, the respective slice is returned if a valid path is provided. 'err' is updated to reflect |
| * the status of the operation. |
| * |
| * Notable status values: |
| * - If a cluster instance corresponding to endpointId and clusterId doesn't exist in the cache, |
| * CHIP_ERROR_KEY_NOT_FOUND shall be returned. |
| * |
| */ |
| const EndpointState * GetEndpointState(EndpointId endpointId, CHIP_ERROR & err) const; |
| const ClusterState * GetClusterState(EndpointId endpointId, ClusterId clusterId, CHIP_ERROR & err) const; |
| const AttributeState * GetAttributeState(EndpointId endpointId, ClusterId clusterId, AttributeId attributeId, |
| CHIP_ERROR & err) const; |
| |
| const EventData * GetEventData(EventNumber number, CHIP_ERROR & err) const; |
| |
| /* |
| * Updates the state of an attribute in the cache given a reader. If the reader is null, the state is updated |
| * with the provided status. |
| */ |
| CHIP_ERROR UpdateCache(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus); |
| |
| /* |
| * If apData is not null, updates the cached event set with the specified event header + payload. |
| * If apData is null and apStatus is not null, the StatusIB is stored in the event status cache. |
| * |
| * Storage of either of these do not affect pre-existing data for the other events in the cache. |
| * |
| */ |
| CHIP_ERROR UpdateEventCache(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus); |
| |
| // |
| // ReadClient::Callback |
| // |
| void OnReportBegin() override; |
| void OnReportEnd() override; |
| void OnAttributeData(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apData, const StatusIB & aStatus) override; |
| void OnError(CHIP_ERROR aError) override { return mCallback.OnError(aError); } |
| |
| void OnEventData(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus) override; |
| |
| void OnDone(ReadClient * apReadClient) override |
| { |
| mRequestPathSet.clear(); |
| return mCallback.OnDone(apReadClient); |
| } |
| |
| void OnSubscriptionEstablished(SubscriptionId aSubscriptionId) override |
| { |
| mCallback.OnSubscriptionEstablished(aSubscriptionId); |
| } |
| |
| CHIP_ERROR OnResubscriptionNeeded(ReadClient * apReadClient, CHIP_ERROR aTerminationCause) override |
| { |
| return mCallback.OnResubscriptionNeeded(apReadClient, aTerminationCause); |
| } |
| |
| void OnDeallocatePaths(chip::app::ReadPrepareParams && aReadPrepareParams) override |
| { |
| mCallback.OnDeallocatePaths(std::move(aReadPrepareParams)); |
| } |
| |
| virtual CHIP_ERROR OnUpdateDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder, |
| const Span<AttributePathParams> & aAttributePaths, |
| bool & aEncodedDataVersionList) override; |
| |
| void OnUnsolicitedMessageFromPublisher(ReadClient * apReadClient) override |
| { |
| return mCallback.OnUnsolicitedMessageFromPublisher(apReadClient); |
| } |
| |
| void OnCASESessionEstablished(const SessionHandle & aSession, ReadPrepareParams & aSubscriptionParams) override |
| { |
| return mCallback.OnCASESessionEstablished(aSession, aSubscriptionParams); |
| } |
| |
| // Commit the pending cluster data version, if there is one. |
| void CommitPendingDataVersion(); |
| |
| // Get our list of data version filters, sorted from larges to smallest by the total size of the TLV |
| // payload for the filter's cluster. Applying filters in this order should maximize space savings |
| // on the wire if not all filters can be applied. |
| void GetSortedFilters(std::vector<std::pair<DataVersionFilter, size_t>> & aVector) const; |
| |
| CHIP_ERROR GetElementTLVSize(TLV::TLVReader * apData, uint32_t & aSize); |
| |
| Callback & mCallback; |
| NodeState mCache; |
| std::set<ConcreteAttributePath> mChangedAttributeSet; |
| std::set<AttributePathParams, Comparator> mRequestPathSet; // wildcard attribute request path only |
| std::vector<EndpointId> mAddedEndpoints; |
| |
| std::set<EventData, EventDataCompare> mEventDataCache; |
| Optional<EventNumber> mHighestReceivedEventNumber; |
| std::map<ConcreteEventPath, StatusIB> mEventStatusCache; |
| BufferedReadCallback mBufferedReader; |
| ConcreteClusterPath mLastReportDataPath = ConcreteClusterPath(kInvalidEndpointId, kInvalidClusterId); |
| const bool mCacheData = CanEnableDataCaching; |
| }; |
| |
| using ClusterStateCache = ClusterStateCacheT<true>; |
| using ClusterStateCacheNoData = ClusterStateCacheT<false>; |
| |
| }; // namespace app |
| }; // namespace chip |
| #endif // CHIP_CONFIG_ENABLE_READ_CLIENT |