From 327448807857ab1d972ad032d7c300d830f14aa1 Mon Sep 17 00:00:00 2001 From: yunhanw Date: Wed, 5 May 2021 06:05:44 -0700 Subject: [PATCH] Add suport to send IM events -- When receiving read requested, store interested event path inside clusterInfo as eventClusterInfoList, reporting engine would fetch events via EventManamgenment from circular event buffers according to eventClusterInfoList, and finally send IM report via reader handler. -- Reconstruct ClusterInfo so that it can represent the intersted attribute and event efficiently. --- src/app/ClusterInfo.h | 39 ++++- src/app/EventManagement.cpp | 24 ++- src/app/EventManagement.h | 19 ++- src/app/InteractionModelEngine.cpp | 30 ++-- src/app/InteractionModelEngine.h | 6 +- src/app/ReadClient.cpp | 49 ++++-- src/app/ReadClient.h | 8 +- src/app/ReadHandler.cpp | 145 +++++++++++++---- src/app/ReadHandler.h | 33 +++- src/app/reporting/Engine.cpp | 153 ++++++++++++++++-- src/app/reporting/Engine.h | 4 +- src/app/tests/TestClusterInfo.cpp | 25 +-- src/app/tests/TestEventLogging.cpp | 6 +- src/app/tests/TestInteractionModelEngine.cpp | 22 +-- src/app/tests/TestReadInteraction.cpp | 4 +- src/app/tests/integration/MockEvents.cpp | 35 ++-- .../tests/integration/chip_im_initiator.cpp | 12 +- .../tests/integration/chip_im_responder.cpp | 8 +- src/app/tests/integration/common.h | 17 +- src/controller/CHIPDeviceController.cpp | 22 +++ 20 files changed, 485 insertions(+), 176 deletions(-) diff --git a/src/app/ClusterInfo.h b/src/app/ClusterInfo.h index 6f65438969470b..ef68b036961740 100644 --- a/src/app/ClusterInfo.h +++ b/src/app/ClusterInfo.h @@ -25,17 +25,42 @@ namespace chip { namespace app { struct ClusterInfo { - ClusterInfo(const AttributePathParams & aAttributePathParams, bool aDirty) : - mAttributePathParams(aAttributePathParams), mDirty(aDirty) - {} + enum class Type : uint8_t + { + kInvalid = 0, + kFieldIdValid = 0x01, + kListIndexValid = 0x02, + kEventIdValid = 0x03, + }; + ClusterInfo() {} bool IsDirty() { return mDirty; } void SetDirty() { mDirty = true; } void ClearDirty() { mDirty = false; } - bool IsSamePath(const ClusterInfo & other) const { return other.mAttributePathParams.IsSamePath(mAttributePathParams); } - AttributePathParams mAttributePathParams; - bool mDirty = false; - ClusterInfo * mpNext = nullptr; + NodeId mNodeId = 0; + ClusterId mClusterId = 0; + ListIndex mListIndex = 0; + FieldId mFieldId = 0; + EndpointId mEndpointId = 0; + bool mDirty = false; + Type mType = Type::kInvalid; + ClusterInfo * mpNext = nullptr; + EventId mEventId = 0; + /* For better structure alignment + * Above ordering is by bit-size to ensure least amount of memory alignment padding. + * Changing order to something more natural (e.g. clusterid before nodeid) will result + * in extra memory alignment padding. + * uint64 mNodeId + * uint16_t mClusterId + * uint16_t mListIndex + * uint8_t FieldId + * uint8_t EndpointId + * uint8_t mDirty + * uint8_t mType + * uint32_t mpNext + * uint16_t EventId + * padding 2 bytes + */ }; } // namespace app } // namespace chip diff --git a/src/app/EventManagement.cpp b/src/app/EventManagement.cpp index 8dc26d08d08c25..4c73ee12fbd255 100644 --- a/src/app/EventManagement.cpp +++ b/src/app/EventManagement.cpp @@ -332,7 +332,7 @@ CHIP_ERROR EventManagement::ConstructEvent(EventLoadOutContext * apContext, Even SuccessOrExit(err); eventDataElementBuilder.EndOfEventDataElement(); - SuccessOrExit(eventDataElementBuilder.GetError()); + SuccessOrExit(err = eventDataElementBuilder.GetError()); err = apContext->mWriter.Finalize(); SuccessOrExit(err); @@ -654,8 +654,10 @@ CHIP_ERROR EventManagement::CopyEventsSince(const TLVReader & aReader, size_t aD return err; } -CHIP_ERROR EventManagement::FetchEventsSince(TLVWriter & aWriter, PriorityLevel aPriority, EventNumber & aEventNumber) +CHIP_ERROR EventManagement::FetchEventsSince(TLVWriter & aWriter, ClusterInfo * apClusterInfolist, PriorityLevel aPriority, + EventNumber & aEventNumber) { + // TODO: Add particular set of event Paths in FetchEventsSince so that we can filter the interested paths CHIP_ERROR err = CHIP_NO_ERROR; const bool recurse = false; TLVReader reader; @@ -787,6 +789,24 @@ CHIP_ERROR EventManagement::ScheduleFlushIfNeeded(EventOptions::Type aUrgent) return CHIP_NO_ERROR; } +void EventManagement::SetScheduledEventEndpoint(EventNumber * apEventEndpoints) +{ + CircularEventBuffer * eventBuffer = mpEventBuffer; + + CriticalSectionEnter(); + + while (eventBuffer != nullptr) + { + if (eventBuffer->GetPriorityLevel() >= PriorityLevel::First && (eventBuffer->GetPriorityLevel() <= PriorityLevel::Last)) + { + apEventEndpoints[static_cast(eventBuffer->GetPriorityLevel())] = eventBuffer->GetLastEventNumber(); + } + eventBuffer = eventBuffer->GetNextCircularEventBuffer(); + } + + CriticalSectionExit(); +} + void CircularEventBuffer::Init(uint8_t * apBuffer, uint32_t aBufferLength, CircularEventBuffer * apPrev, CircularEventBuffer * apNext, PriorityLevel aPriorityLevel) { diff --git a/src/app/EventManagement.h b/src/app/EventManagement.h index f15e87460274cb..c6b8487a816d85 100644 --- a/src/app/EventManagement.h +++ b/src/app/EventManagement.h @@ -28,6 +28,7 @@ #include "EventLoggingDelegate.h" #include "EventLoggingTypes.h" +#include #include #include #include @@ -373,7 +374,7 @@ class EventManagement * will terminate the event writing on event boundary. * * @param[in] aWriter The writer to use for event storage - * + * @param[in] apEventClusterInfolist the interested cluster info list with event path inside * @param[in] aPriority The priority of events to be fetched * * @param[inout] aEventNumber On input, the Event number immediately @@ -394,7 +395,8 @@ class EventManagement * available. * */ - CHIP_ERROR FetchEventsSince(chip::TLV::TLVWriter & aWriter, PriorityLevel aPriority, EventNumber & aEventNumber); + CHIP_ERROR FetchEventsSince(chip::TLV::TLVWriter & aWriter, ClusterInfo * apClusterInfolist, PriorityLevel aPriority, + EventNumber & aEventNumber); /** * @brief @@ -449,6 +451,17 @@ class EventManagement */ EventNumber GetFirstEventNumber(PriorityLevel aPriority); + /** + * @brief + * IsValid returns whether the EventManagement instance is valid + */ + bool IsValid(void) { return EventManagementStates::Shutdown != mState; }; + + /** + * Logger would save last logged event number for each logger buffer into schedule event number array + */ + void SetScheduledEventEndpoint(EventNumber * aEventEndpoints); + private: CHIP_ERROR CalculateEventSize(EventLoggingDelegate * apDelegate, const EventOptions * apOptions, uint32_t & requiredSize); /** @@ -555,7 +568,7 @@ class EventManagement // EventBuffer for debug level, CircularEventBuffer * mpEventBuffer = nullptr; Messaging::ExchangeManager * mpExchangeMgr = nullptr; - EventManagementStates mState = EventManagementStates::Idle; + EventManagementStates mState = EventManagementStates::Shutdown; uint32_t mBytesWritten = 0; }; } // namespace app diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp index 496c788b441977..b43e645a92cde9 100644 --- a/src/app/InteractionModelEngine.cpp +++ b/src/app/InteractionModelEngine.cpp @@ -254,24 +254,23 @@ DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aComman "Default DispatchSingleClusterCommand is called, this should be replaced by actual dispatched for cluster commands"); } -CHIP_ERROR __attribute__((weak)) ReadSingleClusterData(AttributePathParams & aAttributePathParams, TLV::TLVWriter & aWriter) +CHIP_ERROR __attribute__((weak)) ReadSingleClusterData(ClusterInfo & aClusterInfo, TLV::TLVWriter & aWriter) { - ChipLogDetail(DataManagement, - "Received Cluster Command: Cluster=%" PRIx16 " NodeId=%" PRIx64 " Endpoint=%" PRIx8 " FieldId=%" PRIx8 - " ListIndex=%" PRIx8, - aAttributePathParams.mClusterId, aAttributePathParams.mNodeId, aAttributePathParams.mEndpointId, - aAttributePathParams.mFieldId, aAttributePathParams.mListIndex); + ChipLogDetail( + DataManagement, + "Received Cluster Command: Cluster=%" PRIx16 " NodeId=%" PRIx64 " Endpoint=%" PRIx8 " FieldId=%" PRIx8 " ListIndex=%" PRIx8, + aClusterInfo.mClusterId, aClusterInfo.mNodeId, aClusterInfo.mEndpointId, aClusterInfo.mFieldId, aClusterInfo.mListIndex); ChipLogError(DataManagement, "Default ReadSingleClusterData is called, this should be replaced by actual dispatched for cluster"); return CHIP_NO_ERROR; } -CHIP_ERROR __attribute__((weak)) WriteSingleClusterData(AttributePathParams & aAttributePathParams, TLV::TLVReader & aReader) +CHIP_ERROR __attribute__((weak)) WriteSingleClusterData(ClusterInfo & aClusterInfo, TLV::TLVReader & aReader) { ChipLogDetail(DataManagement, "Received Cluster Attribute: Cluster=%" PRIx16 " NodeId=%" PRIx64 " Endpoint=%" PRIx8 " FieldId=%" PRIx8, - " ListIndex=%" PRIx8, aAttributePathParams.mClusterId, aAttributePathParams.mNodeId, - aAttributePathParams.mEndpointId, aAttributePathParams.mFieldId, aAttributePathParams.mListIndex); + " ListIndex=%" PRIx8, aClusterInfo.mClusterId, aClusterInfo.mNodeId, aClusterInfo.mEndpointId, + aClusterInfo.mFieldId, aClusterInfo.mListIndex); ChipLogError(DataManagement, "Default WriteSingleClusterData is called, this should be replaced by actual dispatched for cluster"); return CHIP_NO_ERROR; @@ -296,22 +295,23 @@ void InteractionModelEngine::ReleaseClusterInfoList(ClusterInfo *& aClusterInfo) lastClusterInfo = lastClusterInfo->mpNext; } lastClusterInfo->ClearDirty(); + lastClusterInfo->mType = ClusterInfo::Type::kInvalid; lastClusterInfo->mpNext = mpNextAvailableClusterInfo; mpNextAvailableClusterInfo = aClusterInfo; aClusterInfo = nullptr; } -CHIP_ERROR InteractionModelEngine::PushFront(ClusterInfo *& aClusterInfo, AttributePathParams & aAttributePathParams) +CHIP_ERROR InteractionModelEngine::PushFront(ClusterInfo *& aClusterInfoList, ClusterInfo & aClusterInfo) { - ClusterInfo * last = aClusterInfo; + ClusterInfo * last = aClusterInfoList; if (mpNextAvailableClusterInfo == nullptr) { return CHIP_ERROR_NO_MEMORY; } - aClusterInfo = mpNextAvailableClusterInfo; - mpNextAvailableClusterInfo = mpNextAvailableClusterInfo->mpNext; - aClusterInfo->mpNext = last; - aClusterInfo->mAttributePathParams = aAttributePathParams; + aClusterInfoList = mpNextAvailableClusterInfo; + mpNextAvailableClusterInfo = mpNextAvailableClusterInfo->mpNext; + *aClusterInfoList = aClusterInfo; + aClusterInfoList->mpNext = last; return CHIP_NO_ERROR; } diff --git a/src/app/InteractionModelEngine.h b/src/app/InteractionModelEngine.h index f7475ccf79181f..9f887b4230922f 100644 --- a/src/app/InteractionModelEngine.h +++ b/src/app/InteractionModelEngine.h @@ -131,7 +131,7 @@ class InteractionModelEngine : public Messaging::ExchangeDelegate reporting::Engine & GetReportingEngine() { return mReportingEngine; } void ReleaseClusterInfoList(ClusterInfo *& aClusterInfo); - CHIP_ERROR PushFront(ClusterInfo *& aClusterInfo, AttributePathParams & aAttributePathParams); + CHIP_ERROR PushFront(ClusterInfo *& aClusterInfoLisst, ClusterInfo & aClusterInfo); private: friend class reporting::Engine; @@ -163,7 +163,7 @@ class InteractionModelEngine : public Messaging::ExchangeDelegate void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aCommandId, chip::EndpointId aEndPointId, chip::TLV::TLVReader & aReader, Command * apCommandObj); -CHIP_ERROR ReadSingleClusterData(AttributePathParams & aAttributePathParams, TLV::TLVWriter & aWriter); -CHIP_ERROR WriteSingleClusterData(AttributePathParams & aAttributePathParams, TLV::TLVReader & aReader); +CHIP_ERROR ReadSingleClusterData(ClusterInfo & aClusterInfo, TLV::TLVWriter & aWriter); +CHIP_ERROR WriteSingleClusterData(ClusterInfo & aClusterInfo, TLV::TLVReader & aReader); } // namespace app } // namespace chip diff --git a/src/app/ReadClient.cpp b/src/app/ReadClient.cpp index 9e385eed3f0fbb..e080f3eea66c73 100644 --- a/src/app/ReadClient.cpp +++ b/src/app/ReadClient.cpp @@ -79,8 +79,9 @@ void ReadClient::MoveToState(const ClientState aTargetState) CHIP_ERROR ReadClient::SendReadRequest(NodeId aNodeId, Transport::AdminId aAdminId, EventPathParams * apEventPathParamsList, size_t aEventPathParamsListSize, AttributePathParams * apAttributePathParamsList, - size_t aAttributePathParamsListSize) + size_t aAttributePathParamsListSize, EventNumber aEventNumber) { + // TODO: SendRequest parameter is too long, need to have the structure to represent it CHIP_ERROR err = CHIP_NO_ERROR; System::PacketBufferHandle msgBuf; ChipLogDetail(DataManagement, "%s: Client[%u] [%5.5s]", __func__, @@ -103,13 +104,33 @@ CHIP_ERROR ReadClient::SendReadRequest(NodeId aNodeId, Transport::AdminId aAdmin if (aEventPathParamsListSize != 0 && apEventPathParamsList != nullptr) { - // TODO: fill to construct event paths + EventPathList::Builder & eventPathListBuilder = request.CreateEventPathListBuilder(); + EventPath::Builder eventPathBuilder = eventPathListBuilder.CreateEventPathBuilder(); + for (size_t eventIndex = 0; eventIndex < aEventPathParamsListSize; ++eventIndex) + { + EventPathParams eventPath = apEventPathParamsList[eventIndex]; + eventPathBuilder.NodeId(eventPath.mNodeId) + .EventId(eventPath.mEventId) + .EndpointId(eventPath.mEndpointId) + .ClusterId(eventPath.mClusterId) + .EndOfEventPath(); + SuccessOrExit(err = eventPathBuilder.GetError()); + } + + eventPathListBuilder.EndOfEventPathList(); + SuccessOrExit(err = eventPathListBuilder.GetError()); + + if (aEventNumber != 0) + { + // EventNumber is optional + request.EventNumber(aEventNumber); + } } if (aAttributePathParamsListSize != 0 && apAttributePathParamsList != nullptr) { AttributePathList::Builder attributePathListBuilder = request.CreateAttributePathListBuilder(); - SuccessOrExit(attributePathListBuilder.GetError()); + SuccessOrExit(err = attributePathListBuilder.GetError()); for (size_t index = 0; index < aAttributePathParamsListSize; index++) { AttributePath::Builder attributePathBuilder = attributePathListBuilder.CreateAttributePathBuilder(); @@ -129,11 +150,11 @@ CHIP_ERROR ReadClient::SendReadRequest(NodeId aNodeId, Transport::AdminId aAdmin err = CHIP_ERROR_INVALID_ARGUMENT; ExitNow(); } - SuccessOrExit(attributePathBuilder.GetError()); + SuccessOrExit(err = attributePathBuilder.GetError()); } } request.EndOfReadRequest(); - SuccessOrExit(request.GetError()); + SuccessOrExit(err = request.GetError()); err = writer.Finalize(&msgBuf); SuccessOrExit(err); @@ -293,7 +314,7 @@ CHIP_ERROR ReadClient::ProcessAttributeDataList(TLV::TLVReader & aAttributeDataL chip::TLV::TLVReader dataReader; AttributeDataElement::Parser element; AttributePath::Parser attributePathParser; - AttributePathParams attributePathParams; + ClusterInfo clusterInfo; TLV::TLVReader reader = aAttributeDataListReader; err = element.Init(reader); SuccessOrExit(err); @@ -301,31 +322,31 @@ CHIP_ERROR ReadClient::ProcessAttributeDataList(TLV::TLVReader & aAttributeDataL err = element.GetAttributePath(&attributePathParser); SuccessOrExit(err); - err = attributePathParser.GetNodeId(&(attributePathParams.mNodeId)); + err = attributePathParser.GetNodeId(&(clusterInfo.mNodeId)); SuccessOrExit(err); - err = attributePathParser.GetEndpointId(&(attributePathParams.mEndpointId)); + err = attributePathParser.GetEndpointId(&(clusterInfo.mEndpointId)); SuccessOrExit(err); - err = attributePathParser.GetClusterId(&(attributePathParams.mClusterId)); + err = attributePathParser.GetClusterId(&(clusterInfo.mClusterId)); SuccessOrExit(err); - err = attributePathParser.GetFieldId(&(attributePathParams.mFieldId)); + err = attributePathParser.GetFieldId(&(clusterInfo.mFieldId)); if (CHIP_NO_ERROR == err) { - attributePathParams.mFlags = AttributePathFlags::kFieldIdValid; + clusterInfo.mType = ClusterInfo::Type::kFieldIdValid; } else if (CHIP_END_OF_TLV == err) { - err = attributePathParser.GetListIndex(&(attributePathParams.mListIndex)); + err = attributePathParser.GetListIndex(&(clusterInfo.mListIndex)); SuccessOrExit(err); - attributePathParams.mFlags = AttributePathFlags::kListIndexValid; + clusterInfo.mType = ClusterInfo::Type::kListIndexValid; } SuccessOrExit(err); err = element.GetData(&dataReader); SuccessOrExit(err); - err = WriteSingleClusterData(attributePathParams, dataReader); + err = WriteSingleClusterData(clusterInfo, dataReader); SuccessOrExit(err); } diff --git a/src/app/ReadClient.h b/src/app/ReadClient.h index 2f7189910fab3f..15ad864cc055f1 100644 --- a/src/app/ReadClient.h +++ b/src/app/ReadClient.h @@ -66,18 +66,12 @@ class ReadClient : public Messaging::ExchangeDelegate * until the corresponding InteractionModelDelegate::ReportProcessed or InteractionModelDelegate::ReportError * call happens with guarantee. * - * @param[in] aNodeId Node Id - * @param[in] aAdminId Admin ID - * @param[in] apEventPathParamsList a list of event paths the read client is interested in - * @param[in] aEventPathParamsListSize Number of event paths in apEventPathParamsList - * @param[in] apAttributePathParamsList a list of attribute paths the read client is interested in - * @param[in] aAttributePathParamsListSize Number of attribute paths in apAttributePathParamsList * @retval #others fail to send read request * @retval #CHIP_NO_ERROR On success. */ CHIP_ERROR SendReadRequest(NodeId aNodeId, Transport::AdminId aAdminId, EventPathParams * apEventPathParamsList, size_t aEventPathParamsListSize, AttributePathParams * apAttributePathParamsList, - size_t aAttributePathParamsListSize); + size_t aAttributePathParamsListSize, EventNumber aEventNumber); private: friend class TestReadInteraction; diff --git a/src/app/ReadHandler.cpp b/src/app/ReadHandler.cpp index 9d8441559b58d2..28c60fc66bc0e3 100644 --- a/src/app/ReadHandler.cpp +++ b/src/app/ReadHandler.cpp @@ -35,11 +35,12 @@ CHIP_ERROR ReadHandler::Init(InteractionModelDelegate * apDelegate) // Error if already initialized. VerifyOrExit(apDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mpExchangeCtx == nullptr, err = CHIP_ERROR_INCORRECT_STATE); - mpExchangeCtx = nullptr; - mpDelegate = apDelegate; - mSuppressResponse = true; - mGetToAllEvents = true; - mpClusterInfoList = nullptr; + mpExchangeCtx = nullptr; + mpDelegate = apDelegate; + mSuppressResponse = true; + mpAttributeClusterInfoList = nullptr; + mpEventClusterInfoList = nullptr; + mCurrentPriority = PriorityLevel::Invalid; MoveToState(HandlerState::Initialized); exit: @@ -49,10 +50,14 @@ CHIP_ERROR ReadHandler::Init(InteractionModelDelegate * apDelegate) void ReadHandler::Shutdown() { - InteractionModelEngine::GetInstance()->ReleaseClusterInfoList(mpClusterInfoList); + InteractionModelEngine::GetInstance()->ReleaseClusterInfoList(mpAttributeClusterInfoList); + InteractionModelEngine::GetInstance()->ReleaseClusterInfoList(mpEventClusterInfoList); ClearExistingExchangeContext(); MoveToState(HandlerState::Uninitialized); - mpDelegate = nullptr; + mpDelegate = nullptr; + mpAttributeClusterInfoList = nullptr; + mpEventClusterInfoList = nullptr; + mCurrentPriority = PriorityLevel::Invalid; } CHIP_ERROR ReadHandler::ClearExistingExchangeContext() @@ -72,8 +77,7 @@ CHIP_ERROR ReadHandler::OnReadRequest(Messaging::ExchangeContext * apExchangeCon System::PacketBufferHandle response; mpExchangeCtx = apExchangeContext; - - err = ProcessReadRequest(std::move(aPayload)); + err = ProcessReadRequest(std::move(aPayload)); SuccessOrExit(err); exit: @@ -107,7 +111,6 @@ CHIP_ERROR ReadHandler::ProcessReadRequest(System::PacketBufferHandle aPayload) ReadRequest::Parser readRequestParser; EventPathList::Parser eventPathListParser; AttributePathList::Parser attributePathListParser; - TLV::TLVReader eventPathListReader; reader.Init(std::move(aPayload)); @@ -116,7 +119,6 @@ CHIP_ERROR ReadHandler::ProcessReadRequest(System::PacketBufferHandle aPayload) err = readRequestParser.Init(reader); SuccessOrExit(err); - #if CHIP_CONFIG_IM_ENABLE_SCHEMA_CHECK err = readRequestParser.CheckSchemaValidity(); SuccessOrExit(err); @@ -130,9 +132,9 @@ CHIP_ERROR ReadHandler::ProcessReadRequest(System::PacketBufferHandle aPayload) else { SuccessOrExit(err); - ProcessAttributePathList(attributePathListParser); + err = ProcessAttributePathList(attributePathListParser); } - + SuccessOrExit(err); err = readRequestParser.GetEventPathList(&eventPathListParser); if (err == CHIP_END_OF_TLV) { @@ -141,19 +143,9 @@ CHIP_ERROR ReadHandler::ProcessReadRequest(System::PacketBufferHandle aPayload) else { SuccessOrExit(err); - eventPathListParser.GetReader(&eventPathListReader); - - while (CHIP_NO_ERROR == (err = eventPathListReader.Next())) - { - VerifyOrExit(TLV::AnonymousTag == eventPathListReader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG); - - EventPath::Parser eventPath; - - err = eventPath.Init(eventPathListReader); - SuccessOrExit(err); - // TODO: Pass event path to report engine to generate report with interested events - } + err = ProcessEventPathList(eventPathListParser); } + SuccessOrExit(err); // if we have exhausted this container if (CHIP_END_OF_TLV == err) @@ -180,21 +172,31 @@ CHIP_ERROR ReadHandler::ProcessAttributePathList(AttributePathList::Parser & aAt { VerifyOrExit(TLV::AnonymousTag == reader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG); VerifyOrExit(TLV::kTLVType_List == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); - AttributePathParams attributePathParams; + ClusterInfo clusterInfo; AttributePath::Parser path; err = path.Init(reader); SuccessOrExit(err); - err = path.GetNodeId(&(attributePathParams.mNodeId)); + err = path.GetNodeId(&(clusterInfo.mNodeId)); SuccessOrExit(err); - err = path.GetEndpointId(&(attributePathParams.mEndpointId)); + err = path.GetEndpointId(&(clusterInfo.mEndpointId)); SuccessOrExit(err); - err = path.GetClusterId(&(attributePathParams.mClusterId)); + err = path.GetClusterId(&(clusterInfo.mClusterId)); SuccessOrExit(err); - err = path.GetFieldId(&(attributePathParams.mFieldId)); + err = path.GetFieldId(&(clusterInfo.mFieldId)); + if (CHIP_NO_ERROR == err) + { + clusterInfo.mType = ClusterInfo::Type::kFieldIdValid; + } + else if (CHIP_END_OF_TLV == err) + { + err = path.GetListIndex(&(clusterInfo.mListIndex)); + SuccessOrExit(err); + clusterInfo.mType = ClusterInfo::Type::kListIndexValid; + } SuccessOrExit(err); - err = InteractionModelEngine::GetInstance()->PushFront(mpClusterInfoList, attributePathParams); + err = InteractionModelEngine::GetInstance()->PushFront(mpAttributeClusterInfoList, clusterInfo); SuccessOrExit(err); - mpClusterInfoList->SetDirty(); + mpAttributeClusterInfoList->SetDirty(); } // if we have exhausted this container if (CHIP_END_OF_TLV == err) @@ -207,6 +209,44 @@ CHIP_ERROR ReadHandler::ProcessAttributePathList(AttributePathList::Parser & aAt return err; } +CHIP_ERROR ReadHandler::ProcessEventPathList(EventPathList::Parser & aEventPathListParser) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TLV::TLVReader reader; + aEventPathListParser.GetReader(&reader); + + while (CHIP_NO_ERROR == (err = reader.Next())) + { + VerifyOrExit(TLV::AnonymousTag == reader.GetTag(), err = CHIP_ERROR_INVALID_TLV_TAG); + VerifyOrExit(TLV::kTLVType_List == reader.GetType(), err = CHIP_ERROR_WRONG_TLV_TYPE); + ClusterInfo clusterInfo; + EventPath::Parser path; + err = path.Init(reader); + SuccessOrExit(err); + err = path.GetNodeId(&(clusterInfo.mNodeId)); + SuccessOrExit(err); + err = path.GetEndpointId(&(clusterInfo.mEndpointId)); + SuccessOrExit(err); + err = path.GetClusterId(&(clusterInfo.mClusterId)); + SuccessOrExit(err); + err = path.GetEventId(&(clusterInfo.mEventId)); + SuccessOrExit(err); + clusterInfo.mType = ClusterInfo::Type::kEventIdValid; + err = InteractionModelEngine::GetInstance()->PushFront(mpEventClusterInfoList, clusterInfo); + SuccessOrExit(err); + } + + // if we have exhausted this container + if (CHIP_END_OF_TLV == err) + { + err = CHIP_NO_ERROR; + } + +exit: + ChipLogFunctError(err); + return err; +} + const char * ReadHandler::GetStateStr() const { #if CHIP_DETAIL_LOGGING @@ -231,5 +271,46 @@ void ReadHandler::MoveToState(const HandlerState aTargetState) ChipLogDetail(DataManagement, "IM RH moving to [%s]", GetStateStr()); } +bool ReadHandler::CheckEventClean(EventManagement & aEventManager) +{ + if (mCurrentPriority == PriorityLevel::Invalid) + { + // Upload is not in middle, previous mLastScheduledEventNumber is not valid, Check for new events, and set a checkpoint + for (size_t index = 0; index < ArraySize(mSelfProcessedEvents); index++) + { + EventNumber lastEventNumber = aEventManager.GetLastEventNumber(static_cast(index)); + if ((lastEventNumber != 0) && (lastEventNumber >= mSelfProcessedEvents[index])) + { + // We have more events. snapshot last event IDs + aEventManager.SetScheduledEventEndpoint(&(mLastScheduledEventNumber[0])); + // initialize the next priority level to transfer + MoveToNextScheduledDirtyPriority(); + return false; + } + } + return true; + } + else + { + // Upload is in middle, previous mLastScheduledEventNumber is still valid, recheck via MoveToNextScheduledDirtyPriority, + // if finally mCurrentPriority is invalid, it means no more event + MoveToNextScheduledDirtyPriority(); + return mCurrentPriority == PriorityLevel::Invalid; + } +} + +void ReadHandler::MoveToNextScheduledDirtyPriority() +{ + for (uint8_t i = 0; i < ArraySize(mSelfProcessedEvents); i++) + { + if ((mLastScheduledEventNumber[i] != 0) && mSelfProcessedEvents[i] <= mLastScheduledEventNumber[i]) + { + mCurrentPriority = static_cast(i); + return; + } + } + + mCurrentPriority = PriorityLevel::Invalid; +} } // namespace app } // namespace chip diff --git a/src/app/ReadHandler.h b/src/app/ReadHandler.h index 2c8a3057d2d1ce..968bd0fcf8c312 100644 --- a/src/app/ReadHandler.h +++ b/src/app/ReadHandler.h @@ -25,6 +25,7 @@ #pragma once #include +#include #include #include #include @@ -100,7 +101,18 @@ class ReadHandler virtual ~ReadHandler() = default; - ClusterInfo * GetCluterInfolist() { return mpClusterInfoList; }; + ClusterInfo * GetAttributeClusterInfolist() { return mpAttributeClusterInfoList; } + ClusterInfo * GetEventClusterInfolist() { return mpEventClusterInfoList; } + EventNumber * GetVendedEventNumberList() { return mSelfProcessedEvents; } + PriorityLevel GetCurrentPriority() { return mCurrentPriority; } + + // if current priority is in the middle, it has valid snapshoted last event number, it check cleaness via comparing + // with snapshotted last event number. if current priority is in the end, no valid + // sanpshotted last event, check with latest last event number, re-setup snapshoted checkpoint, and compare again. + bool CheckEventClean(EventManagement & aEventManager); + + // Move to the next dirty priority where last schedule event number is larger than current self vended event number + void MoveToNextScheduledDirtyPriority(); private: enum class HandlerState @@ -112,6 +124,7 @@ class ReadHandler CHIP_ERROR ProcessReadRequest(System::PacketBufferHandle aPayload); CHIP_ERROR ProcessAttributePathList(AttributePathList::Parser & aAttributePathListParser); + CHIP_ERROR ProcessEventPathList(EventPathList::Parser & aEventPathListParser); void MoveToState(const HandlerState aTargetState); const char * GetStateStr() const; @@ -121,14 +134,20 @@ class ReadHandler InteractionModelDelegate * mpDelegate = nullptr; // Don't need the response for report data if true - bool mSuppressResponse; - - // Retrieve all events - bool mGetToAllEvents; + bool mSuppressResponse = false; // Current Handler state - HandlerState mState; - ClusterInfo * mpClusterInfoList = nullptr; + HandlerState mState = HandlerState::Uninitialized; + ClusterInfo * mpAttributeClusterInfoList = nullptr; + ClusterInfo * mpEventClusterInfoList = nullptr; + + PriorityLevel mCurrentPriority = PriorityLevel::Invalid; + + // The event number of the last processed event for each priority level + EventNumber mSelfProcessedEvents[kNumPriorityLevel]; + + // The last schedule event number snapshoted in the beginning when preparing to fill new events to reports + EventNumber mLastScheduledEventNumber[kNumPriorityLevel]; }; } // namespace app } // namespace chip diff --git a/src/app/reporting/Engine.cpp b/src/app/reporting/Engine.cpp index 332231ede3a8c2..71f00b1699ce77 100644 --- a/src/app/reporting/Engine.cpp +++ b/src/app/reporting/Engine.cpp @@ -37,23 +37,37 @@ CHIP_ERROR Engine::Init() return CHIP_NO_ERROR; } +EventNumber Engine::CountEvents(ReadHandler * apReadHandler, EventNumber * apInitialEvents) +{ + EventNumber event_count = 0; + EventNumber * vendedEventNumberList = apReadHandler->GetVendedEventNumberList(); + for (size_t index = 0; index < kNumPriorityLevel; index++) + { + if (vendedEventNumberList[index] > apInitialEvents[index]) + { + event_count += vendedEventNumberList[index] - apInitialEvents[index]; + } + } + return event_count; +} + CHIP_ERROR Engine::RetrieveClusterData(AttributeDataElement::Builder & aAttributeDataElementBuilder, ClusterInfo & aClusterInfo) { CHIP_ERROR err = CHIP_NO_ERROR; TLV::TLVType type = TLV::kTLVType_NotSpecified; AttributePath::Builder attributePathBuilder = aAttributeDataElementBuilder.CreateAttributePathBuilder(); - attributePathBuilder.NodeId(aClusterInfo.mAttributePathParams.mNodeId) - .EndpointId(aClusterInfo.mAttributePathParams.mEndpointId) - .ClusterId(aClusterInfo.mAttributePathParams.mClusterId) - .FieldId(aClusterInfo.mAttributePathParams.mFieldId) + attributePathBuilder.NodeId(aClusterInfo.mNodeId) + .EndpointId(aClusterInfo.mEndpointId) + .ClusterId(aClusterInfo.mClusterId) + .FieldId(aClusterInfo.mFieldId) .EndOfAttributePath(); err = attributePathBuilder.GetError(); SuccessOrExit(err); aAttributeDataElementBuilder.GetWriter()->StartContainer(TLV::ContextTag(AttributeDataElement::kCsTag_Data), TLV::kTLVType_Structure, type); - err = ReadSingleClusterData(aClusterInfo.mAttributePathParams, *(aAttributeDataElementBuilder.GetWriter())); + err = ReadSingleClusterData(aClusterInfo, *(aAttributeDataElementBuilder.GetWriter())); SuccessOrExit(err); aAttributeDataElementBuilder.GetWriter()->EndContainer(type); aAttributeDataElementBuilder.DataVersion(0).MoreClusterData(false).EndOfAttributeDataElement(); @@ -65,8 +79,7 @@ Engine::RetrieveClusterData(AttributeDataElement::Builder & aAttributeDataElemen if (err != CHIP_NO_ERROR) { - ChipLogError(DataManagement, "Error retrieving data from clusterId: %08x, err = %d", - aClusterInfo.mAttributePathParams.mClusterId, err); + ChipLogError(DataManagement, "Error retrieving data from clusterId: %08x, err = %d", aClusterInfo.mClusterId, err); } return err; @@ -75,17 +88,16 @@ Engine::RetrieveClusterData(AttributeDataElement::Builder & aAttributeDataElemen CHIP_ERROR Engine::BuildSingleReportDataAttributeDataList(ReportData::Builder & reportDataBuilder, ReadHandler * apReadHandler) { CHIP_ERROR err = CHIP_NO_ERROR; - ClusterInfo * clusterInfo = apReadHandler->GetCluterInfolist(); + ClusterInfo * clusterInfo = apReadHandler->GetAttributeClusterInfolist(); AttributeDataList::Builder attributeDataList = reportDataBuilder.CreateAttributeDataListBuilder(); - SuccessOrExit(reportDataBuilder.GetError()); + SuccessOrExit(err = reportDataBuilder.GetError()); // TODO: Need to handle multiple chunk of message while (clusterInfo != nullptr) { if (clusterInfo->IsDirty()) { AttributeDataElement::Builder attributeDataElementBuilder = attributeDataList.CreateAttributeDataElementBuilder(); - ChipLogDetail(DataManagement, " Cluster %u, Field %u is dirty", clusterInfo->mAttributePathParams.mClusterId, - clusterInfo->mAttributePathParams.mFieldId); + ChipLogDetail(DataManagement, " Cluster %u, Field %u is dirty", clusterInfo->mClusterId, clusterInfo->mFieldId); // Retrieve data for this cluster instance and clear its dirty flag. err = RetrieveClusterData(attributeDataElementBuilder, *clusterInfo); VerifyOrExit(err == CHIP_NO_ERROR, @@ -94,12 +106,123 @@ CHIP_ERROR Engine::BuildSingleReportDataAttributeDataList(ReportData::Builder & clusterInfo = clusterInfo->mpNext; } + attributeDataList.EndOfAttributeDataList(); + err = attributeDataList.GetError(); exit: ChipLogFunctError(err); return err; } +CHIP_ERROR Engine::BuildSingleReportDataEventList(ReportData::Builder & aReportDataBuilder, ReadHandler * apReadHandler) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + EventNumber eventCount = 0; + TLV::TLVWriter backup; + bool eventClean = true; + EventNumber initialEvents[kNumPriorityLevel]; + ClusterInfo * clusterInfoList = apReadHandler->GetEventClusterInfolist(); + EventNumber * eventNumberList = apReadHandler->GetVendedEventNumberList(); + EventManagement & eventManager = EventManagement::GetInstance(); + EventList::Builder eventList; + + VerifyOrExit(clusterInfoList != nullptr, ); + + aReportDataBuilder.Checkpoint(backup); + + VerifyOrExit(apReadHandler != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + + eventList = aReportDataBuilder.CreateEventDataListBuilder(); + SuccessOrExit(err = eventList.GetError()); + + memcpy(initialEvents, eventNumberList, sizeof(initialEvents)); + // If the eventManager is not valid or has not been initialized, + // skip the rest of processing + VerifyOrExit(eventManager.IsValid(), err = CHIP_ERROR_INCORRECT_STATE); + + for (size_t index = 0; index < kNumPriorityLevel; index++) + { + EventNumber tmpNumber = eventManager.GetFirstEventNumber(static_cast(index)); + if (tmpNumber > initialEvents[index]) + { + initialEvents[index] = tmpNumber; + } + } + + eventClean = apReadHandler->CheckEventClean(eventManager); + + // proceed only if there are new events. + if (eventClean) + { + aReportDataBuilder.Rollback(backup); + ExitNow(); // Read clean, move along + } + + while (apReadHandler->GetCurrentPriority() != PriorityLevel::Invalid) + { + uint8_t priorityIndex = static_cast(apReadHandler->GetCurrentPriority()); + err = eventManager.FetchEventsSince(*(eventList.GetWriter()), clusterInfoList, apReadHandler->GetCurrentPriority(), + eventNumberList[priorityIndex]); + + if ((err == CHIP_END_OF_TLV) || (err == CHIP_ERROR_TLV_UNDERRUN) || (err == CHIP_NO_ERROR)) + { + // We have successfully reached the end of the log for + // the current priority. Advance to the next + // priority level. + err = CHIP_NO_ERROR; + apReadHandler->MoveToNextScheduledDirtyPriority(); + mMoreChunkedMessages = false; + } + else if ((err == CHIP_ERROR_BUFFER_TOO_SMALL) || (err == CHIP_ERROR_NO_MEMORY)) + { + eventCount = CountEvents(apReadHandler, initialEvents); + + // when first cluster event is too big to fit in the packet, ignore that cluster event. + if (eventCount == 0) + { + eventNumberList[priorityIndex]++; + ChipLogDetail(DataManagement, " first cluster event is too big so that it fails to fit in the packet!"); + err = CHIP_NO_ERROR; + } + else + { + // `FetchEventsSince` has filled the available space + // within the allowed buffer before it fit all the + // available events. This is an expected condition, + // so we do not propagate the error to higher levels; + // instead, we terminate the event processing for now + // (we will get another chance immediately afterwards, + // with a ew buffer) and do not advance the processing + // to the next priority level. + err = CHIP_NO_ERROR; + break; + } + mMoreChunkedMessages = true; + } + else + { + // All other errors are propagated to higher level. + // Exiting here and returning an error will lead to + // abandoning subscription. + ExitNow(); + } + } + + eventList.EndOfEventList(); + SuccessOrExit(err = eventList.GetError()); + + eventCount = CountEvents(apReadHandler, initialEvents); + ChipLogDetail(DataManagement, "Fetched %d events", eventCount); + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DataManagement, "Error retrieving events, err = %d", err); + } + + return err; +} + CHIP_ERROR Engine::BuildAndSendSingleReportData(ReadHandler * apReadHandler) { CHIP_ERROR err = CHIP_NO_ERROR; @@ -117,9 +240,9 @@ CHIP_ERROR Engine::BuildAndSendSingleReportData(ReadHandler * apReadHandler) err = BuildSingleReportDataAttributeDataList(reportDataBuilder, apReadHandler); SuccessOrExit(err); - // TODO: Fill in the EventList. - // err = BuildSingleReportDataEventList(reportDataBuilder, apReadHandler); - // SuccessOrExit(err); + + err = BuildSingleReportDataEventList(reportDataBuilder, apReadHandler); + SuccessOrExit(err); // TODO: Add mechanism to set mSuppressResponse to handle status reports for multiple reports // TODO: Add more chunk message support, currently mMoreChunkedMessages is always false. @@ -129,7 +252,7 @@ CHIP_ERROR Engine::BuildAndSendSingleReportData(ReadHandler * apReadHandler) } reportDataBuilder.EndOfReportData(); - SuccessOrExit(reportDataBuilder.GetError()); + SuccessOrExit(err = reportDataBuilder.GetError()); err = reportDataWriter.Finalize(&bufHandle); SuccessOrExit(err); diff --git a/src/app/reporting/Engine.h b/src/app/reporting/Engine.h index 9c41172e5e2c25..efa0d5a56f5f9e 100644 --- a/src/app/reporting/Engine.h +++ b/src/app/reporting/Engine.h @@ -79,8 +79,10 @@ class Engine CHIP_ERROR BuildAndSendSingleReportData(ReadHandler * apReadHandler); CHIP_ERROR BuildSingleReportDataAttributeDataList(ReportData::Builder & reportDataBuilder, ReadHandler * apReadHandler); - + CHIP_ERROR BuildSingleReportDataEventList(ReportData::Builder & reportDataBuilder, ReadHandler * apReadHandler); CHIP_ERROR RetrieveClusterData(AttributeDataElement::Builder & aAttributeDataElementBuilder, ClusterInfo & aClusterInfo); + EventNumber CountEvents(ReadHandler * apReadHandler, EventNumber * apInitialEvents); + /** * Send Report via ReadHandler * diff --git a/src/app/tests/TestClusterInfo.cpp b/src/app/tests/TestClusterInfo.cpp index 0fcca3490c36ae..16a19a22b5bfac 100644 --- a/src/app/tests/TestClusterInfo.cpp +++ b/src/app/tests/TestClusterInfo.cpp @@ -29,28 +29,9 @@ namespace chip { namespace app { namespace TestClusterInfo { -void TestSamePath(nlTestSuite * apSuite, void * apContext) -{ - AttributePathParams attributePathParams1(1, 2, 3, 4, 5, AttributePathFlags::kFieldIdValid); - AttributePathParams attributePathParams2(1, 2, 3, 4, 5, AttributePathFlags::kFieldIdValid); - ClusterInfo clusterInfo1(attributePathParams1, false); - ClusterInfo clusterInfo2(attributePathParams2, false); - NL_TEST_ASSERT(apSuite, clusterInfo1.IsSamePath(clusterInfo2)); -} - -void TestDifferentPath(nlTestSuite * apSuite, void * apContext) -{ - AttributePathParams attributePathParams1(1, 2, 3, 4, 5, AttributePathFlags::kFieldIdValid); - AttributePathParams attributePathParams2(6, 2, 3, 4, 5, AttributePathFlags::kFieldIdValid); - ClusterInfo clusterInfo1(attributePathParams1, false); - ClusterInfo clusterInfo2(attributePathParams2, false); - NL_TEST_ASSERT(apSuite, !clusterInfo1.IsSamePath(clusterInfo2)); -} - void TestDirty(nlTestSuite * apSuite, void * apContext) { - AttributePathParams attributePathParams1(1, 2, 3, 4, 5, AttributePathFlags::kFieldIdValid); - ClusterInfo clusterInfo1(attributePathParams1, false); + ClusterInfo clusterInfo1; clusterInfo1.SetDirty(); NL_TEST_ASSERT(apSuite, clusterInfo1.IsDirty()); clusterInfo1.ClearDirty(); @@ -61,9 +42,7 @@ void TestDirty(nlTestSuite * apSuite, void * apContext) } // namespace chip namespace { -const nlTest sTests[] = { NL_TEST_DEF("TestSamePath", chip::app::TestClusterInfo::TestSamePath), - NL_TEST_DEF("TestDifferentPath", chip::app::TestClusterInfo::TestDifferentPath), - NL_TEST_DEF("TestDirty", chip::app::TestClusterInfo::TestDirty), NL_TEST_SENTINEL() }; +const nlTest sTests[] = { NL_TEST_DEF("TestDirty", chip::app::TestClusterInfo::TestDirty), NL_TEST_SENTINEL() }; } int TestClusterInfo() diff --git a/src/app/tests/TestEventLogging.cpp b/src/app/tests/TestEventLogging.cpp index b7e46dcf06efac..e391ad7304bb69 100644 --- a/src/app/tests/TestEventLogging.cpp +++ b/src/app/tests/TestEventLogging.cpp @@ -22,6 +22,7 @@ * */ +#include #include #include #include @@ -145,8 +146,9 @@ static void CheckLogReadOut(nlTestSuite * apSuite, chip::app::EventManagement & uint8_t backingStore[1024]; size_t elementCount; writer.Init(backingStore, 1024); - - err = alogMgmt.FetchEventsSince(writer, priority, startingEventNumber); + chip::app::ClusterInfo testClusterInfo; + testClusterInfo.mEventId = 1; + err = alogMgmt.FetchEventsSince(writer, &testClusterInfo, priority, startingEventNumber); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR || err == CHIP_END_OF_TLV); reader.Init(backingStore, writer.GetLengthWritten()); diff --git a/src/app/tests/TestInteractionModelEngine.cpp b/src/app/tests/TestInteractionModelEngine.cpp index 098bf6330bb7c4..d6d043120e4fb6 100644 --- a/src/app/tests/TestInteractionModelEngine.cpp +++ b/src/app/tests/TestInteractionModelEngine.cpp @@ -76,20 +76,24 @@ void TestInteractionModelEngine::TestClusterInfoPushRelease(nlTestSuite * apSuit err = InteractionModelEngine::GetInstance()->Init(&gExchangeManager, nullptr); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); ClusterInfo * clusterInfoList = nullptr; - AttributePathParams attributePathParams1(1, 2, 3, 4, 5, AttributePathFlags::kFieldIdValid); - AttributePathParams attributePathParams2(2, 3, 4, 5, 6, AttributePathFlags::kFieldIdValid); - AttributePathParams attributePathParams3(3, 4, 5, 6, 7, AttributePathFlags::kFieldIdValid); + ClusterInfo clusterInfo1; + ClusterInfo clusterInfo2; + ClusterInfo clusterInfo3; - InteractionModelEngine::GetInstance()->PushFront(clusterInfoList, attributePathParams1); - NL_TEST_ASSERT(apSuite, clusterInfoList != nullptr && clusterInfoList->mAttributePathParams.IsSamePath(attributePathParams1)); + clusterInfo1.mEndpointId = 1; + clusterInfo2.mEndpointId = 2; + clusterInfo3.mEndpointId = 3; + + InteractionModelEngine::GetInstance()->PushFront(clusterInfoList, clusterInfo1); + NL_TEST_ASSERT(apSuite, clusterInfoList != nullptr && clusterInfo1.mEndpointId == clusterInfoList->mEndpointId); NL_TEST_ASSERT(apSuite, GetClusterInfoListLength(clusterInfoList) == 1); - InteractionModelEngine::GetInstance()->PushFront(clusterInfoList, attributePathParams2); - NL_TEST_ASSERT(apSuite, clusterInfoList != nullptr && clusterInfoList->mAttributePathParams.IsSamePath(attributePathParams2)); + InteractionModelEngine::GetInstance()->PushFront(clusterInfoList, clusterInfo2); + NL_TEST_ASSERT(apSuite, clusterInfoList != nullptr && clusterInfo2.mEndpointId == clusterInfoList->mEndpointId); NL_TEST_ASSERT(apSuite, GetClusterInfoListLength(clusterInfoList) == 2); - InteractionModelEngine::GetInstance()->PushFront(clusterInfoList, attributePathParams3); - NL_TEST_ASSERT(apSuite, clusterInfoList != nullptr && clusterInfoList->mAttributePathParams.IsSamePath(attributePathParams3)); + InteractionModelEngine::GetInstance()->PushFront(clusterInfoList, clusterInfo3); + NL_TEST_ASSERT(apSuite, clusterInfoList != nullptr && clusterInfo3.mEndpointId == clusterInfoList->mEndpointId); NL_TEST_ASSERT(apSuite, GetClusterInfoListLength(clusterInfoList) == 3); InteractionModelEngine::GetInstance()->ReleaseClusterInfoList(clusterInfoList); diff --git a/src/app/tests/TestReadInteraction.cpp b/src/app/tests/TestReadInteraction.cpp index 4df7aa083a7bbf..7af271004eef78 100644 --- a/src/app/tests/TestReadInteraction.cpp +++ b/src/app/tests/TestReadInteraction.cpp @@ -88,13 +88,15 @@ void TestReadInteraction::TestReadClient(nlTestSuite * apSuite, void * apContext CHIP_ERROR err = CHIP_NO_ERROR; app::ReadClient readClient; + EventNumber eventNumber = 0; System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); err = readClient.Init(&gExchangeManager, nullptr); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); err = readClient.SendReadRequest(kTestDeviceNodeId, gAdminId, nullptr /*apEventPathParamsList*/, 0 /*aEventPathParamsListSize*/, - nullptr /*apAttributePathParamsList*/, 0 /*aAttributePathParamsListSize*/); + nullptr /*apAttributePathParamsList*/, 0 /*aAttributePathParamsListSize*/, + eventNumber /*aEventNumber*/); NL_TEST_ASSERT(apSuite, err == CHIP_ERROR_INCORRECT_STATE); GenerateReportData(apSuite, apContext, buf); diff --git a/src/app/tests/integration/MockEvents.cpp b/src/app/tests/integration/MockEvents.cpp index d38a3978c3dec7..bd57eb3d97f3bf 100644 --- a/src/app/tests/integration/MockEvents.cpp +++ b/src/app/tests/integration/MockEvents.cpp @@ -24,6 +24,7 @@ */ #include "MockEvents.h" +#include "common.h" #include #include #include @@ -31,15 +32,11 @@ #include #include #include +#include -static const chip::NodeId kTestNodeId = 0x18B4300000000001ULL; -static const chip::NodeId kTestNodeId1 = 0x18B4300000000002ULL; -static const chip::ClusterId kLivenessClusterId = 0x00000022; -static const uint32_t kLivenessChangeEvent = 1; -static const chip::EndpointId kTestEndpointId = 2; -static const uint64_t kLivenessDeviceStatus = chip::TLV::ContextTag(1); -static bool gMockEventStop = false; -static bool gEventIsStopped = false; +static uint64_t kLivenessDeviceStatus = chip::TLV::ContextTag(1); +static bool gMockEventStop = false; +static bool gEventIsStopped = false; EventGenerator::EventGenerator(size_t aNumStates, size_t aInitialState) : mNumStates(aNumStates), mState(aInitialState) {} @@ -56,43 +53,43 @@ void LivenessEventGenerator::Generate(void) switch (mState) { case 0: - LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); + LogLiveness(chip::kTestDeviceNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); break; case 1: - LogLiveness(kTestNodeId1, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); + LogLiveness(chip::kTestDeviceNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); break; case 2: - LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); + LogLiveness(chip::kTestDeviceNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); break; case 3: - LogLiveness(kTestNodeId1, kTestEndpointId, LIVENESS_DEVICE_STATUS_UNREACHABLE); + LogLiveness(chip::kTestDeviceNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_UNREACHABLE); break; case 4: - LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); + LogLiveness(chip::kTestDeviceNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); break; case 5: - LogLiveness(kTestNodeId1, kTestEndpointId, LIVENESS_DEVICE_STATUS_REBOOTING); + LogLiveness(chip::kTestDeviceNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_REBOOTING); break; case 6: - LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); + LogLiveness(chip::kTestDeviceNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); break; case 7: - LogLiveness(kTestNodeId1, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); + LogLiveness(chip::kTestDeviceNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); break; case 8: - LogLiveness(kTestNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); + LogLiveness(chip::kTestDeviceNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); break; case 9: - LogLiveness(kTestNodeId1, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); + LogLiveness(chip::kTestDeviceNodeId, kTestEndpointId, LIVENESS_DEVICE_STATUS_ONLINE); break; default: @@ -115,7 +112,7 @@ chip::EventNumber LivenessEventGenerator::LogLiveness(chip::NodeId aNodeId, chip chip::app::EventManagement & logManager = chip::app::EventManagement::GetInstance(); chip::EventNumber number = 0; chip::app::EventSchema schema = { - aNodeId, aEndpointId, kLivenessClusterId, kLivenessChangeEvent, chip::app::PriorityLevel::Critical, + aNodeId, aEndpointId, kTestClusterId, kLivenessChangeEvent, chip::app::PriorityLevel::Critical, }; chip::app::EventOptions options; mStatus = static_cast(aStatus); diff --git a/src/app/tests/integration/chip_im_initiator.cpp b/src/app/tests/integration/chip_im_initiator.cpp index ebeed0df259bec..d1ac99de60b580 100644 --- a/src/app/tests/integration/chip_im_initiator.cpp +++ b/src/app/tests/integration/chip_im_initiator.cpp @@ -128,13 +128,17 @@ CHIP_ERROR SendCommandRequest(void) CHIP_ERROR SendReadRequest(void) { - CHIP_ERROR err = CHIP_NO_ERROR; + CHIP_ERROR err = CHIP_NO_ERROR; + chip::EventNumber number = 0; + chip::app::EventPathParams eventPathParams(chip::kTestDeviceNodeId, kTestEndpointId, kTestClusterId, kLivenessChangeEvent, + false /*not urgent*/); + chip::app::AttributePathParams attributePathParams(chip::kTestDeviceNodeId, kTestEndpointId, kTestClusterId, 1, 0, chip::app::AttributePathFlags::kFieldIdValid); printf("\nSend read request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId); - err = gpReadClient->SendReadRequest(chip::kTestDeviceNodeId, gAdminId, nullptr, 0, &attributePathParams, 1); + err = gpReadClient->SendReadRequest(chip::kTestDeviceNodeId, gAdminId, &eventPathParams, 1, &attributePathParams, 1, number); SuccessOrExit(err); if (err == CHIP_NO_ERROR) @@ -265,9 +269,9 @@ void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aC } } -CHIP_ERROR WriteSingleClusterData(AttributePathParams & aAttributePathParams, TLV::TLVReader & aReader) +CHIP_ERROR WriteSingleClusterData(ClusterInfo & aClusterInfo, TLV::TLVReader & aReader) { - if (aAttributePathParams.mClusterId != kTestClusterId || aAttributePathParams.mEndpointId != kTestEndpointId) + if (aClusterInfo.mClusterId != kTestClusterId || aClusterInfo.mEndpointId != kTestEndpointId) { return CHIP_ERROR_INVALID_ARGUMENT; } diff --git a/src/app/tests/integration/chip_im_responder.cpp b/src/app/tests/integration/chip_im_responder.cpp index c3c1bcfdd60157..2273c8c75c3acc 100644 --- a/src/app/tests/integration/chip_im_responder.cpp +++ b/src/app/tests/integration/chip_im_responder.cpp @@ -97,18 +97,18 @@ void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aC return; } -CHIP_ERROR ReadSingleClusterData(AttributePathParams & aAttributePathParams, TLV::TLVWriter & aWriter) +CHIP_ERROR ReadSingleClusterData(ClusterInfo & aClusterInfo, TLV::TLVWriter & aWriter) { CHIP_ERROR err = CHIP_NO_ERROR; - VerifyOrExit(aAttributePathParams.mClusterId == kTestClusterId && aAttributePathParams.mEndpointId == kTestEndpointId, + VerifyOrExit(aClusterInfo.mClusterId == kTestClusterId && aClusterInfo.mEndpointId == kTestEndpointId, err = CHIP_ERROR_INVALID_ARGUMENT); - if (aAttributePathParams.mFieldId == kRootFieldId || aAttributePathParams.mFieldId == 1) + if (aClusterInfo.mFieldId == kRootFieldId || aClusterInfo.mFieldId == 1) { err = aWriter.Put(TLV::ContextTag(kTestFieldId1), kTestFieldValue1); SuccessOrExit(err); } - if (aAttributePathParams.mFieldId == kRootFieldId || aAttributePathParams.mFieldId == 2) + if (aClusterInfo.mFieldId == kRootFieldId || aClusterInfo.mFieldId == 2) { err = aWriter.Put(TLV::ContextTag(kTestFieldId2), kTestFieldValue2); SuccessOrExit(err); diff --git a/src/app/tests/integration/common.h b/src/app/tests/integration/common.h index 2b69ebf07e2565..97c1ceea3108e8 100644 --- a/src/app/tests/integration/common.h +++ b/src/app/tests/integration/common.h @@ -32,14 +32,15 @@ extern chip::Messaging::ExchangeManager gExchangeManager; -constexpr chip::ClusterId kTestClusterId = 6; -constexpr chip::CommandId kTestCommandId = 40; -constexpr chip::EndpointId kTestEndpointId = 1; -constexpr chip::GroupId kTestGroupId = 0; -constexpr chip::FieldId kTestFieldId1 = 1; -constexpr chip::FieldId kTestFieldId2 = 2; -constexpr uint8_t kTestFieldValue1 = 1; -constexpr uint8_t kTestFieldValue2 = 2; +constexpr chip::ClusterId kTestClusterId = 6; +constexpr chip::CommandId kTestCommandId = 40; +constexpr chip::EndpointId kTestEndpointId = 1; +constexpr chip::GroupId kTestGroupId = 0; +constexpr chip::FieldId kTestFieldId1 = 1; +constexpr chip::FieldId kTestFieldId2 = 2; +constexpr uint8_t kTestFieldValue1 = 1; +constexpr uint8_t kTestFieldValue2 = 2; +constexpr chip::EventId kLivenessChangeEvent = 1; void InitializeChip(void); void ShutdownChip(void); void TLVPrettyPrinter(const char * aFormat, ...); diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 6e12937efe5253..fc1d9825664d46 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -1074,3 +1074,25 @@ void DeviceCommissioner::OnSessionEstablishmentTimeoutCallback(System::Layer * a } // namespace Controller } // namespace chip + +namespace chip { +namespace Platform { +namespace PersistedStorage { + +/* +* Dummy implementations of PersistedStorage platform methods. These aren't +* used in the context of the Device Controller, but are required to satisfy +* the linker. +*/ + +CHIP_ERROR Read(const char *aKey, uint32_t &aValue) { + return CHIP_NO_ERROR; +} + +CHIP_ERROR Write(const char *aKey, uint32_t aValue) { + return CHIP_NO_ERROR; +} + +} +} +}