|  | /* | 
|  | * | 
|  | *    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/TLV.h" | 
|  | #include "system/SystemPacketBuffer.h" | 
|  | #include "system/TLVPacketBufferBackingStore.h" | 
|  | #include <app/AppConfig.h> | 
|  | #include <app/AttributePathParams.h> | 
|  | #include <app/ReadClient.h> | 
|  | #include <vector> | 
|  |  | 
|  | #if CHIP_CONFIG_ENABLE_READ_CLIENT | 
|  | namespace chip { | 
|  | namespace app { | 
|  |  | 
|  | /* | 
|  | * This is an adapter that intercepts calls that deliver data from the ReadClient, | 
|  | * selectively buffers up list chunks in TLV and reconstitutes them into a singular, contiguous TLV array | 
|  | * upon completion of delivery of all chunks. This is then delivered to a compliant ReadClient::Callback | 
|  | * without any awareness on their part that chunking happened. | 
|  | * | 
|  | */ | 
|  | class BufferedReadCallback : public ReadClient::Callback | 
|  | { | 
|  | public: | 
|  | BufferedReadCallback(Callback & callback) : mCallback(callback) {} | 
|  |  | 
|  | private: | 
|  | /* | 
|  | * Generates the reconsistuted TLV array from the stored individual list elements | 
|  | */ | 
|  | CHIP_ERROR GenerateListTLV(TLV::ScopedBufferTLVReader & reader); | 
|  |  | 
|  | /* | 
|  | * Dispatch any buffered list data if we need to. Buffered data will only be dispatched if: | 
|  | *  1. The path provided in aPath is different from the buffered path being tracked internally AND the type of data | 
|  | *     in the buffer is list data | 
|  | * | 
|  | *     OR | 
|  | * | 
|  | *  2. The path provided in aPath is similar to what is buffered but we've hit the end of the report. | 
|  | * | 
|  | */ | 
|  | CHIP_ERROR DispatchBufferedData(const ConcreteAttributePath & aPath, const StatusIB & aStatus, bool aEndOfReport = false); | 
|  |  | 
|  | /* | 
|  | * Buffer up list data as they arrive. | 
|  | */ | 
|  | CHIP_ERROR BufferData(const ConcreteDataAttributePath & aPath, TLV::TLVReader * apReader); | 
|  |  | 
|  | // | 
|  | // 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 | 
|  | { | 
|  | mBufferedList.clear(); | 
|  | return mCallback.OnError(aError); | 
|  | } | 
|  |  | 
|  | void OnEventData(const EventHeader & aEventHeader, TLV::TLVReader * apData, const StatusIB * apStatus) override | 
|  | { | 
|  | return mCallback.OnEventData(aEventHeader, apData, apStatus); | 
|  | } | 
|  |  | 
|  | void OnDone(ReadClient * apReadClient) override { 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 | 
|  | { | 
|  | return mCallback.OnDeallocatePaths(std::move(aReadPrepareParams)); | 
|  | } | 
|  |  | 
|  | virtual CHIP_ERROR OnUpdateDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder, | 
|  | const Span<AttributePathParams> & aAttributePaths, | 
|  | bool & aEncodedDataVersionList) override | 
|  | { | 
|  | return mCallback.OnUpdateDataVersionFilterList(aDataVersionFilterIBsBuilder, aAttributePaths, aEncodedDataVersionList); | 
|  | } | 
|  |  | 
|  | virtual CHIP_ERROR GetHighestReceivedEventNumber(Optional<EventNumber> & aEventNumber) override | 
|  | { | 
|  | return mCallback.GetHighestReceivedEventNumber(aEventNumber); | 
|  | } | 
|  |  | 
|  | void OnUnsolicitedMessageFromPublisher(ReadClient * apReadClient) override | 
|  | { | 
|  | return mCallback.OnUnsolicitedMessageFromPublisher(apReadClient); | 
|  | } | 
|  |  | 
|  | void OnCASESessionEstablished(const SessionHandle & aSession, ReadPrepareParams & aSubscriptionParams) override | 
|  | { | 
|  | return mCallback.OnCASESessionEstablished(aSession, aSubscriptionParams); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Given a reader positioned at a list element, allocate a packet buffer, copy the list item where | 
|  | * the reader is positioned into that buffer and add it to our buffered list for tracking. | 
|  | * | 
|  | * This should be called in list index order starting from the lowest index that needs to be buffered. | 
|  | * | 
|  | */ | 
|  | CHIP_ERROR BufferListItem(TLV::TLVReader & reader); | 
|  | ConcreteDataAttributePath mBufferedPath; | 
|  | std::vector<System::PacketBufferHandle> mBufferedList; | 
|  | Callback & mCallback; | 
|  | }; | 
|  |  | 
|  | } // namespace app | 
|  | } // namespace chip | 
|  | #endif // CHIP_CONFIG_ENABLE_READ_CLIENT |