Skip to content

Commit 01b5137

Browse files
authored
[IM] Notify AttributeAccessInterface for end of list (project-chip#16670)
* [IM] Notify AttributeAccessInterface for end of list * Address comments * Fix * Resolve iOS build issue * Clean & Restyle * Address comments * Address comments, fixes the case related to nullable lists * Remove redundant comment and clearify the comment * Address comments * Address comments and reformat * Fix dirty merge, try to reduce rom usage * Try to save code size
1 parent 9924308 commit 01b5137

18 files changed

+610
-58
lines changed

src/app/AttributeAccessInterface.h

+27
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,33 @@ class AttributeAccessInterface
414414
*/
415415
virtual CHIP_ERROR Write(const ConcreteDataAttributePath & aPath, AttributeValueDecoder & aDecoder) { return CHIP_NO_ERROR; }
416416

417+
/**
418+
* Indicates the start of a series of list operations. This function will be called before the first Write operation of a series
419+
* of consequence attribute data of the same attribute.
420+
*
421+
* 1) This function will be called if the client tries to set a nullable list attribute to null.
422+
* 2) This function will only be called once for a series of consequent attribute data (regardless the kind of list operation)
423+
* of the same attribute.
424+
*
425+
* @param [in] aPath indicates the path of the modified list.
426+
*/
427+
virtual void OnListWriteBegin(const ConcreteAttributePath & aPath) {}
428+
429+
/**
430+
* Indicates the end of a series of list operations. This function will be called after the last Write operation of a series
431+
* of consequence attribute data of the same attribute.
432+
*
433+
* 1) This function will be called if the client tries to set a nullable list attribute to null.
434+
* 2) This function will only be called once for a series of consequent attribute data (regardless the kind of list operation)
435+
* of the same attribute.
436+
* 3) When aWriteWasSuccessful is true, the data written must be consistent or the list is untouched.
437+
*
438+
* @param [in] aPath indicates the path of the modified list
439+
* @param [in] aWriteWasSuccessful indicates whether the delivered list is complete.
440+
*
441+
*/
442+
virtual void OnListWriteEnd(const ConcreteAttributePath & aPath, bool aWriteWasSuccessful) {}
443+
417444
/**
418445
* Mechanism for keeping track of a chain of AttributeAccessInterfaces.
419446
*/

src/app/ChunkedWriteCallback.cpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void ChunkedWriteCallback::OnResponse(const WriteClient * apWriteClient, const C
2525
{
2626
// We may send a chunked list. To make the behavior consistent whether a list is being chunked or not,
2727
// we merge the write responses for a chunked list here and provide our consumer with a single status response.
28-
if (mLastAttributePath.HasValue())
28+
if (mProcessingAttributePath.HasValue())
2929
{
3030
// This is not the first write response.
3131
if (IsAppendingToLastItem(aPath))
@@ -40,7 +40,7 @@ void ChunkedWriteCallback::OnResponse(const WriteClient * apWriteClient, const C
4040
}
4141

4242
// This is a response to another attribute write. Report the final result of last attribute write.
43-
callback->OnResponse(apWriteClient, mLastAttributePath.Value(), mAttributeStatus);
43+
callback->OnResponse(apWriteClient, mProcessingAttributePath.Value(), mAttributeStatus);
4444
}
4545

4646
// This is the first report for a new attribute. We assume it will never be a list item operation.
@@ -49,7 +49,7 @@ void ChunkedWriteCallback::OnResponse(const WriteClient * apWriteClient, const C
4949
aStatus = StatusIB(CHIP_ERROR_INCORRECT_STATE);
5050
}
5151

52-
mLastAttributePath.SetValue(aPath);
52+
mProcessingAttributePath.SetValue(aPath);
5353
mAttributeStatus = aStatus;
5454
// For the last status in the response, we will call the application callback in OnDone()
5555
}
@@ -61,12 +61,12 @@ void ChunkedWriteCallback::OnError(const WriteClient * apWriteClient, CHIP_ERROR
6161

6262
void ChunkedWriteCallback::OnDone(WriteClient * apWriteClient)
6363
{
64-
if (mLastAttributePath.HasValue())
64+
if (mProcessingAttributePath.HasValue())
6565
{
6666
// We have a cached status that has yet to be reported to the application so report it now.
6767
// If we failed to receive the response, or we received a malformed response, OnResponse won't be called,
68-
// mLastAttributePath will be Missing() in this case.
69-
callback->OnResponse(apWriteClient, mLastAttributePath.Value(), mAttributeStatus);
68+
// mProcessingAttributePath will be Missing() in this case.
69+
callback->OnResponse(apWriteClient, mProcessingAttributePath.Value(), mAttributeStatus);
7070
}
7171

7272
callback->OnDone(apWriteClient);
@@ -78,7 +78,7 @@ bool ChunkedWriteCallback::IsAppendingToLastItem(const ConcreteDataAttributePath
7878
{
7979
return false;
8080
}
81-
if (!mLastAttributePath.HasValue() || !(mLastAttributePath.Value() == aPath))
81+
if (!mProcessingAttributePath.HasValue() || !(mProcessingAttributePath.Value() == aPath))
8282
{
8383
return false;
8484
}

src/app/ChunkedWriteCallback.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class ChunkedWriteCallback : public WriteClient::Callback
4545

4646
// We are using the casts between ConcreteAttributePath and ConcreteDataAttributePath, then all paths passed to upper
4747
// applications will always have NotList as mListOp.
48-
Optional<ConcreteAttributePath> mLastAttributePath;
48+
Optional<ConcreteAttributePath> mProcessingAttributePath;
4949
StatusIB mAttributeStatus;
5050

5151
WriteClient::Callback * callback;

src/app/ConcreteAttributePath.h

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ struct ConcreteAttributePath : public ConcreteClusterPath
5353
return ConcreteClusterPath::operator==(aOther) && (mAttributeId == aOther.mAttributeId);
5454
}
5555

56+
bool operator!=(const ConcreteAttributePath & aOther) const { return !(*this == aOther); }
57+
5658
bool operator<(const ConcreteAttributePath & path) const
5759
{
5860
return (mEndpointId < path.mEndpointId) || ((mEndpointId == path.mEndpointId) && (mClusterId < path.mClusterId)) ||

src/app/InteractionModelEngine.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ CHIP_ERROR InteractionModelEngine::PushFrontAttributePathList(ObjectList<Attribu
571571
CHIP_ERROR err = PushFront(aAttributePathList, aAttributePath, mAttributePathPool);
572572
if (err == CHIP_ERROR_NO_MEMORY)
573573
{
574-
ChipLogError(InteractionModel, "AttributePath pool full, cannot handle more entries!");
574+
ChipLogError(InteractionModel, "AttributePath pool full");
575575
}
576576
return err;
577577
}
@@ -587,7 +587,7 @@ CHIP_ERROR InteractionModelEngine::PushFrontEventPathParamsList(ObjectList<Event
587587
CHIP_ERROR err = PushFront(aEventPathList, aEventPath, mEventPathPool);
588588
if (err == CHIP_ERROR_NO_MEMORY)
589589
{
590-
ChipLogError(InteractionModel, "EventPath pool full, cannot handle more entries!");
590+
ChipLogError(InteractionModel, "EventPath pool full");
591591
}
592592
return err;
593593
}
@@ -603,7 +603,7 @@ CHIP_ERROR InteractionModelEngine::PushFrontDataVersionFilterList(ObjectList<Dat
603603
CHIP_ERROR err = PushFront(aDataVersionFilterList, aDataVersionFilter, mDataVersionFilterPool);
604604
if (err == CHIP_ERROR_NO_MEMORY)
605605
{
606-
ChipLogError(InteractionModel, "DataVersionFilter pool full, cannot handle more entries, reset this error and continue!");
606+
ChipLogError(InteractionModel, "DataVersionFilter pool full, ignore this filter");
607607
err = CHIP_NO_ERROR;
608608
}
609609
return err;

src/app/InteractionModelEngine.h

+15
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#include <app/WriteClient.h>
5757
#include <app/WriteHandler.h>
5858
#include <app/reporting/Engine.h>
59+
#include <app/util/attribute-metadata.h>
5960
#include <app/util/basic-types.h>
6061

6162
namespace chip {
@@ -380,6 +381,13 @@ CHIP_ERROR ReadSingleClusterData(const Access::SubjectDescriptor & aSubjectDescr
380381
const ConcreteReadAttributePath & aPath, AttributeReportIBs::Builder & aAttributeReports,
381382
AttributeValueEncoder::AttributeEncodeState * apEncoderState);
382383

384+
/**
385+
* Get the registered attribute access override. nullptr when attribute access override is not found.
386+
*
387+
* TODO(#16806): This function and registerAttributeAccessOverride can be member functions of InteractionModelEngine.
388+
*/
389+
AttributeAccessInterface * GetAttributeAccessOverride(EndpointId aEndpointId, ClusterId aClusterId);
390+
383391
/**
384392
* TODO: Document.
385393
*/
@@ -397,5 +405,12 @@ bool IsClusterDataVersionEqual(const ConcreteClusterPath & aConcreteClusterPath,
397405
*/
398406
bool IsDeviceTypeOnEndpoint(DeviceTypeId deviceType, EndpointId endpoint);
399407

408+
/**
409+
* Returns the metadata of the attribute for the given path.
410+
*
411+
* @retval The metadata of the attribute, will return null if the given attribute does not exists.
412+
*/
413+
const EmberAfAttributeMetadata * GetAttributeMetadata(const ConcreteAttributePath & aConcreteClusterPath);
414+
400415
} // namespace app
401416
} // namespace chip

0 commit comments

Comments
 (0)