LCOV - code coverage report
Current view: top level - app - AttributeAccessInterface.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 41 41 100.0 %
Date: 2024-02-15 08:20:41 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2021 Project CHIP Authors
       4             :  *    All rights reserved.
       5             :  *
       6             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7             :  *    you may not use this file except in compliance with the License.
       8             :  *    You may obtain a copy of the License at
       9             :  *
      10             :  *        http://www.apache.org/licenses/LICENSE-2.0
      11             :  *
      12             :  *    Unless required by applicable law or agreed to in writing, software
      13             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15             :  *    See the License for the specific language governing permissions and
      16             :  *    limitations under the License.
      17             :  */
      18             : 
      19             : #include <app/AttributeAccessInterface.h>
      20             : 
      21             : namespace chip {
      22             : namespace app {
      23             : 
      24        3214 : CHIP_ERROR AttributeReportBuilder::PrepareAttribute(AttributeReportIBs::Builder & aAttributeReportIBsBuilder,
      25             :                                                     const ConcreteDataAttributePath & aPath, DataVersion aDataVersion)
      26             : {
      27        3214 :     AttributeReportIB::Builder & attributeReportIBBuilder = aAttributeReportIBsBuilder.CreateAttributeReport();
      28        3214 :     ReturnErrorOnFailure(aAttributeReportIBsBuilder.GetError());
      29             : 
      30        3203 :     AttributeDataIB::Builder & attributeDataIBBuilder = attributeReportIBBuilder.CreateAttributeData();
      31        3203 :     ReturnErrorOnFailure(attributeReportIBBuilder.GetError());
      32             : 
      33        3185 :     attributeDataIBBuilder.DataVersion(aDataVersion);
      34             : 
      35        3185 :     AttributePathIB::Builder & attributePathIBBuilder = attributeDataIBBuilder.CreatePath();
      36        3185 :     ReturnErrorOnFailure(attributeDataIBBuilder.GetError());
      37             : 
      38        3143 :     attributePathIBBuilder.Endpoint(aPath.mEndpointId).Cluster(aPath.mClusterId).Attribute(aPath.mAttributeId);
      39             : 
      40        3143 :     if (aPath.mListOp == ConcreteDataAttributePath::ListOperation::AppendItem)
      41             :     {
      42             :         // An append to a list (or a data chunk consisting just one list entry that's part of a bigger list) is represented by a
      43             :         // null list index in the path.
      44         312 :         attributePathIBBuilder.ListIndex(DataModel::Nullable<ListIndex>());
      45             :     }
      46             : 
      47        3143 :     ReturnErrorOnFailure(attributePathIBBuilder.EndOfAttributePathIB());
      48             : 
      49        3088 :     return attributeDataIBBuilder.GetError();
      50             : }
      51             : 
      52        3068 : CHIP_ERROR AttributeReportBuilder::FinishAttribute(AttributeReportIBs::Builder & aAttributeReportIBsBuilder)
      53             : {
      54        3068 :     ReturnErrorOnFailure(aAttributeReportIBsBuilder.GetAttributeReport().GetAttributeData().EndOfAttributeDataIB());
      55        3068 :     return aAttributeReportIBsBuilder.GetAttributeReport().EndOfAttributeReportIB();
      56             : }
      57             : 
      58             : namespace {
      59             : 
      60             : constexpr uint32_t kEndOfListByteCount = 1;
      61             : // 2 bytes: one to end the AttributeDataIB and one to end the AttributeReportIB.
      62             : constexpr uint32_t kEndOfAttributeReportIBByteCount = 2;
      63             : constexpr TLV::TLVType kAttributeDataIBType         = TLV::kTLVType_Structure;
      64             : 
      65             : } // anonymous namespace
      66             : 
      67        1431 : CHIP_ERROR AttributeValueEncoder::EnsureListStarted()
      68             : {
      69        1431 :     VerifyOrDie(mCurrentEncodingListIndex == kInvalidListIndex);
      70             : 
      71        1431 :     mEncodingInitialList = (mEncodeState.mCurrentEncodingListIndex == kInvalidListIndex);
      72        1431 :     if (mEncodingInitialList)
      73             :     {
      74             :         // Clear mAllowPartialData flag here since this encode procedure is not atomic.
      75             :         // The most common error in this function is CHIP_ERROR_NO_MEMORY / CHIP_ERROR_BUFFER_TOO_SMALL, just revert and try
      76             :         // next time is ok.
      77        1293 :         mEncodeState.mAllowPartialData = false;
      78             : 
      79             :         AttributeReportBuilder builder;
      80             : 
      81        1293 :         mPath.mListOp = ConcreteDataAttributePath::ListOperation::ReplaceAll;
      82        1293 :         ReturnErrorOnFailure(builder.PrepareAttribute(mAttributeReportIBsBuilder, mPath, mDataVersion));
      83             : 
      84        1198 :         auto * attributeDataWriter = mAttributeReportIBsBuilder.GetAttributeReport().GetAttributeData().GetWriter();
      85             :         TLV::TLVType outerType;
      86        1198 :         ReturnErrorOnFailure(
      87             :             attributeDataWriter->StartContainer(TLV::ContextTag(AttributeDataIB::Tag::kData), TLV::kTLVType_Array, outerType));
      88        1190 :         VerifyOrDie(outerType == kAttributeDataIBType);
      89             : 
      90             :         // Instead of reserving hardcoded amounts, we could checkpoint the
      91             :         // writer, encode array end and FinishAttribute, check that this fits,
      92             :         // measure how much the writer advanced, then restore the checkpoint,
      93             :         // reserve the measured value, and save it.  But that's probably more
      94             :         // cycles than just reserving this known constant.
      95        1190 :         ReturnErrorOnFailure(
      96             :             mAttributeReportIBsBuilder.GetWriter()->ReserveBuffer(kEndOfAttributeReportIBByteCount + kEndOfListByteCount));
      97             : 
      98        1178 :         mEncodeState.mCurrentEncodingListIndex = 0;
      99             :     }
     100             :     else
     101             :     {
     102             :         // For all elements in the list, a report with append operation will be generated. This will not be changed during encoding
     103             :         // of each report since the users cannot access mPath.
     104         138 :         mPath.mListOp = ConcreteDataAttributePath::ListOperation::AppendItem;
     105             :     }
     106             : 
     107        1316 :     mCurrentEncodingListIndex = 0;
     108             : 
     109             :     // After encoding the initial list start, the remaining items are atomically encoded into the buffer. Tell report engine to not
     110             :     // revert partial data.
     111        1316 :     mEncodeState.mAllowPartialData = true;
     112             : 
     113        1316 :     return CHIP_NO_ERROR;
     114             : }
     115             : 
     116        1316 : void AttributeValueEncoder::EnsureListEnded()
     117             : {
     118        1316 :     if (!mEncodingInitialList)
     119             :     {
     120             :         // Nothing to do.
     121         138 :         return;
     122             :     }
     123             : 
     124             :     // Unreserve the space we reserved just for this.  Crash if anything here
     125             :     // fails, because that would mean that we've corrupted our data, and since
     126             :     // mEncodeState.mAllowPartialData is true nothing will clean up for us here.
     127        1178 :     auto * attributeDataWriter = mAttributeReportIBsBuilder.GetAttributeReport().GetAttributeData().GetWriter();
     128        1178 :     VerifyOrDie(attributeDataWriter->UnreserveBuffer(kEndOfListByteCount + kEndOfAttributeReportIBByteCount) == CHIP_NO_ERROR);
     129        1178 :     VerifyOrDie(attributeDataWriter->EndContainer(kAttributeDataIBType) == CHIP_NO_ERROR);
     130             : 
     131             :     AttributeReportBuilder builder;
     132        1178 :     VerifyOrDie(builder.FinishAttribute(mAttributeReportIBsBuilder) == CHIP_NO_ERROR);
     133             : 
     134        1178 :     if (!mEncodedAtLeastOneListItem)
     135             :     {
     136             :         // If we have not managed to encode any list items, we don't actually
     137             :         // want to output the single "empty list" IB that will then be followed
     138             :         // by one-IB-per-item in the next packet.  Just have the reporting
     139             :         // engine roll back our entire attribute and put us in the next packet.
     140             :         //
     141             :         // If we succeeded at encoding the whole list (i.e. the list is in fact
     142             :         // empty and we fit in the packet), mAllowPartialData will be ignored,
     143             :         // so it's safe to set it to false even if encoding succeeded.
     144         427 :         mEncodeState.mAllowPartialData = false;
     145             :     }
     146             : }
     147             : 
     148             : } // namespace app
     149             : } // namespace chip

Generated by: LCOV version 1.14