diff --git a/src/app/InteractionModelDelegate.h b/src/app/InteractionModelDelegate.h index aba65f4ade432a..1e3bca90b47b75 100644 --- a/src/app/InteractionModelDelegate.h +++ b/src/app/InteractionModelDelegate.h @@ -50,62 +50,6 @@ class ReadHandler; class InteractionModelDelegate { public: - /** - * Notification that the interaction model has received a list of events in response to a Read request and that list - * of events needs to be processed. - * @param[in] apExchangeContext An exchange context that represents the exchange the Report Data came in on. - * This can be used to recover the NodeId of the node that sent the Report Data. - * It is managed externally and should not be closed by the SDK consumer. - * @param[in] apEventListReader TLV reader positioned at the list that contains the events. The - * implementation of EventStreamReceived is expected to call Next() on the reader to - * advance it to the first element of the list, then process the elements from beginning to the - * end. The callee is expected to consume all events. - * - * @retval # CHIP_ERROR_NOT_IMPLEMENTED if not implemented - */ - virtual CHIP_ERROR EventStreamReceived(const Messaging::ExchangeContext * apExchangeContext, TLV::TLVReader * apEventListReader) - { - return CHIP_ERROR_NOT_IMPLEMENTED; - } - - /** - * Notification that the interaction model has received a list of attribute data in response to a Read request. apData might be - * nullptr if status is not Status::Success. - * - * @param[in] apReadClient The read client object, the application can use GetAppIdentifier() for the read client to - * distinguish different read requests. - * @param[in] aPath The path of the attribute, contains node id, endpoint id, cluster id, field id etc. - * @param[in] apData The attribute data TLV - * @param[in] status Interaction model status code - * - */ - virtual void OnReportData(const ReadClient * apReadClient, const ClusterInfo & aPath, TLV::TLVReader * apData, - Protocols::InteractionModel::Status status) - {} - - /** - * Notification that the last message for a Report Data action for the given ReadClient has been received and processed. - * @param[in] apReadClient A current readClient which can identify the read to the consumer, particularly during - * multiple read interactions - * @retval # CHIP_ERROR_NOT_IMPLEMENTED if not implemented - */ - virtual CHIP_ERROR ReportProcessed(const ReadClient * apReadClient) { return CHIP_ERROR_NOT_IMPLEMENTED; } - - /** - * Notification that a read attempt encountered an asynchronous failure. - * @param[in] apReadClient A current readClient which can identify the read to the consumer, particularly during - * multiple read interactions - * @param[in] aError A error that could be CHIP_ERROR_TIMEOUT when read client fails to receive, or other error when - * fail to process report data. - * @retval # CHIP_ERROR_NOT_IMPLEMENTED if not implemented - */ - virtual CHIP_ERROR ReadError(ReadClient * apReadClient, CHIP_ERROR aError) { return CHIP_ERROR_NOT_IMPLEMENTED; } - - /** - * Notification that a Subscribe Response has been processed and application can do further work . - */ - virtual CHIP_ERROR SubscribeResponseProcessed(const ReadClient * apReadClient) { return CHIP_ERROR_NOT_IMPLEMENTED; } - /** * Notification that Subscription has been established successfully and application can do further work in handler. */ @@ -116,14 +60,6 @@ class InteractionModelDelegate */ virtual CHIP_ERROR SubscriptionTerminated(const ReadHandler * apReadHandler) { return CHIP_ERROR_NOT_IMPLEMENTED; } - /** - * Notification that a read interaction was completed on the client successfully. - * @param[in] apReadClient A current read client which can identify the read client to the consumer, particularly - * during multiple read interactions - * @retval # CHIP_ERROR_NOT_IMPLEMENTED if not implemented - */ - virtual CHIP_ERROR ReadDone(ReadClient * apReadClient) { return CHIP_ERROR_NOT_IMPLEMENTED; } - virtual ~InteractionModelDelegate() = default; }; diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp index 2c33beeec2487d..06c859a2c7f6b0 100644 --- a/src/app/InteractionModelEngine.cpp +++ b/src/app/InteractionModelEngine.cpp @@ -121,14 +121,8 @@ void InteractionModelEngine::Shutdown() } CHIP_ERROR InteractionModelEngine::NewReadClient(ReadClient ** const apReadClient, ReadClient::InteractionType aInteractionType, - uint64_t aAppIdentifier, InteractionModelDelegate * apDelegateOverride) + ReadClient::Callback * aCallback) { - - if (apDelegateOverride == nullptr) - { - apDelegateOverride = mpDelegate; - } - *apReadClient = nullptr; for (auto & readClient : mReadClients) @@ -138,7 +132,7 @@ CHIP_ERROR InteractionModelEngine::NewReadClient(ReadClient ** const apReadClien CHIP_ERROR err; *apReadClient = &readClient; - err = readClient.Init(mpExchangeMgr, apDelegateOverride, aInteractionType, aAppIdentifier); + err = readClient.Init(mpExchangeMgr, aCallback, aInteractionType); if (CHIP_NO_ERROR != err) { *apReadClient = nullptr; @@ -428,11 +422,11 @@ void InteractionModelEngine::OnResponseTimeout(Messaging::ExchangeContext * ec) ChipLogValueExchange(ec)); } -CHIP_ERROR InteractionModelEngine::SendReadRequest(ReadPrepareParams & aReadPrepareParams, uint64_t aAppIdentifier) +CHIP_ERROR InteractionModelEngine::SendReadRequest(ReadPrepareParams & aReadPrepareParams, ReadClient::Callback * aCallback) { ReadClient * client = nullptr; CHIP_ERROR err = CHIP_NO_ERROR; - ReturnErrorOnFailure(NewReadClient(&client, ReadClient::InteractionType::Read, aAppIdentifier)); + ReturnErrorOnFailure(NewReadClient(&client, ReadClient::InteractionType::Read, aCallback)); err = client->SendReadRequest(aReadPrepareParams); if (err != CHIP_NO_ERROR) { @@ -441,10 +435,10 @@ CHIP_ERROR InteractionModelEngine::SendReadRequest(ReadPrepareParams & aReadPrep return err; } -CHIP_ERROR InteractionModelEngine::SendSubscribeRequest(ReadPrepareParams & aReadPrepareParams, uint64_t aAppIdentifier) +CHIP_ERROR InteractionModelEngine::SendSubscribeRequest(ReadPrepareParams & aReadPrepareParams, ReadClient::Callback * aCallback) { ReadClient * client = nullptr; - ReturnErrorOnFailure(NewReadClient(&client, ReadClient::InteractionType::Subscribe, aAppIdentifier)); + ReturnErrorOnFailure(NewReadClient(&client, ReadClient::InteractionType::Subscribe, aCallback)); ReturnErrorOnFailure(client->SendSubscribeRequest(aReadPrepareParams)); return CHIP_NO_ERROR; } diff --git a/src/app/InteractionModelEngine.h b/src/app/InteractionModelEngine.h index 9194beaa4841a9..fec05f058738bf 100644 --- a/src/app/InteractionModelEngine.h +++ b/src/app/InteractionModelEngine.h @@ -101,7 +101,7 @@ class InteractionModelEngine : public Messaging::ExchangeDelegate, public Comman * @retval #CHIP_ERROR_NO_MEMORY If there is no ReadClient available * @retval #CHIP_NO_ERROR On success. */ - CHIP_ERROR SendReadRequest(ReadPrepareParams & aReadPrepareParams, uint64_t aAppIdentifier = 0); + CHIP_ERROR SendReadRequest(ReadPrepareParams & aReadPrepareParams, ReadClient::Callback * aCallback); /** * Creates a new read client and sends SubscribeRequest message to the node using the read client. @@ -110,7 +110,7 @@ class InteractionModelEngine : public Messaging::ExchangeDelegate, public Comman * @retval #CHIP_ERROR_NO_MEMORY If there is no ReadClient available * @retval #CHIP_NO_ERROR On success. */ - CHIP_ERROR SendSubscribeRequest(ReadPrepareParams & aReadPrepareParams, uint64_t aAppIdentifier = 0); + CHIP_ERROR SendSubscribeRequest(ReadPrepareParams & aReadPrepareParams, ReadClient::Callback * aCallback); /** * Tears down an active subscription. @@ -151,7 +151,7 @@ class InteractionModelEngine : public Messaging::ExchangeDelegate, public Comman * @retval #CHIP_NO_ERROR On success. */ CHIP_ERROR NewReadClient(ReadClient ** const apReadClient, ReadClient::InteractionType aInteractionType, - uint64_t aAppIdentifier, InteractionModelDelegate * apDelegateOverride = nullptr); + ReadClient::Callback * aCallback); uint32_t GetNumActiveReadHandlers() const; uint32_t GetNumActiveReadClients() const; diff --git a/src/app/ReadClient.cpp b/src/app/ReadClient.cpp index 0e7ab15fe6e33a..ba263eb4ae021a 100644 --- a/src/app/ReadClient.cpp +++ b/src/app/ReadClient.cpp @@ -29,8 +29,7 @@ namespace chip { namespace app { -CHIP_ERROR ReadClient::Init(Messaging::ExchangeManager * apExchangeMgr, InteractionModelDelegate * apDelegate, - InteractionType aInteractionType, uint64_t aAppIdentifier) +CHIP_ERROR ReadClient::Init(Messaging::ExchangeManager * apExchangeMgr, Callback * apCallback, InteractionType aInteractionType) { CHIP_ERROR err = CHIP_NO_ERROR; // Error if already initialized. @@ -38,9 +37,8 @@ CHIP_ERROR ReadClient::Init(Messaging::ExchangeManager * apExchangeMgr, Interact VerifyOrExit(apExchangeMgr != nullptr, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mpExchangeMgr == nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); mpExchangeMgr = apExchangeMgr; - mpDelegate = apDelegate; + mpCallback = apCallback; mState = ClientState::Initialized; - mAppIdentifier = aAppIdentifier; mMinIntervalFloorSeconds = 0; mMaxIntervalCeilingSeconds = 0; mSubscriptionId = 0; @@ -60,17 +58,14 @@ void ReadClient::Shutdown() void ReadClient::ShutdownInternal(CHIP_ERROR aError) { - if (mpDelegate != nullptr) + if (mpCallback != nullptr) { if (aError != CHIP_NO_ERROR) { - mpDelegate->ReadError(this, aError); + mpCallback->OnError(this, aError); } - else - { - mpDelegate->ReadDone(this); - } - mpDelegate = nullptr; + mpCallback->OnDone(this); + mpCallback = nullptr; } if (IsSubscriptionType()) { @@ -122,7 +117,7 @@ CHIP_ERROR ReadClient::SendReadRequest(ReadPrepareParams & aReadPrepareParams) ChipLogDetail(DataManagement, "%s: Client[%u] [%5.5s]", __func__, InteractionModelEngine::GetInstance()->GetReadClientArrayIndex(this), GetStateStr()); VerifyOrExit(ClientState::Initialized == mState, err = CHIP_ERROR_INCORRECT_STATE); - VerifyOrExit(mpDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mpCallback != nullptr, err = CHIP_ERROR_INCORRECT_STATE); // Discard any existing exchange context. Effectively we can only have one exchange per ReadClient // at any one time. @@ -290,7 +285,7 @@ CHIP_ERROR ReadClient::OnMessageReceived(Messaging::ExchangeContext * apExchange { CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrExit(!IsFree(), err = CHIP_ERROR_INCORRECT_STATE); - VerifyOrExit(mpDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mpCallback != nullptr, err = CHIP_ERROR_INCORRECT_STATE); if (aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::ReportData)) { err = ProcessReportData(std::move(aPayload)); @@ -411,12 +406,11 @@ CHIP_ERROR ReadClient::ProcessReportData(System::PacketBufferHandle && aPayload) } SuccessOrExit(err); - if (isEventListPresent && nullptr != mpDelegate) + if (isEventListPresent && nullptr != mpCallback) { chip::TLV::TLVReader eventListReader; eventList.GetReader(&eventListReader); - err = mpDelegate->EventStreamReceived(mpExchangeCtx, &eventListReader); - SuccessOrExit(err); + mpCallback->OnEventData(this, eventListReader); } err = report.GetAttributeDataList(&attributeDataList); @@ -426,7 +420,7 @@ CHIP_ERROR ReadClient::ProcessReportData(System::PacketBufferHandle && aPayload) err = CHIP_NO_ERROR; } SuccessOrExit(err); - if (isAttributeDataListPresent && nullptr != mpDelegate && !moreChunkedMessages) + if (isAttributeDataListPresent && nullptr != mpCallback && !moreChunkedMessages) { chip::TLV::TLVReader attributeDataListReader; attributeDataList.GetReader(&attributeDataListReader); @@ -440,10 +434,6 @@ CHIP_ERROR ReadClient::ProcessReportData(System::PacketBufferHandle && aPayload) // are multiple reports } - if (err == CHIP_NO_ERROR) - { - mpDelegate->ReportProcessed(this); - } exit: SendStatusResponse(err); if (!mInitialReport) @@ -524,7 +514,9 @@ CHIP_ERROR ReadClient::ProcessAttributeDataList(TLV::TLVReader & aAttributeDataL { ExitNow(); } - mpDelegate->OnReportData(this, clusterInfo, &dataReader, status); + mpCallback->OnAttributeData( + this, ConcreteAttributePath(clusterInfo.mEndpointId, clusterInfo.mClusterId, clusterInfo.mFieldId), + status == Protocols::InteractionModel::Status::Success ? &dataReader : nullptr, StatusIB(status)); } if (CHIP_END_OF_TLV == err) @@ -591,7 +583,11 @@ CHIP_ERROR ReadClient::ProcessSubscribeResponse(System::PacketBufferHandle && aP VerifyOrReturnLogError(IsMatchingClient(subscriptionId), CHIP_ERROR_INVALID_ARGUMENT); ReturnLogErrorOnFailure(subscribeResponse.GetMinIntervalFloorSeconds(&mMinIntervalFloorSeconds)); ReturnLogErrorOnFailure(subscribeResponse.GetMaxIntervalCeilingSeconds(&mMaxIntervalCeilingSeconds)); - mpDelegate->SubscribeResponseProcessed(this); + + if (mpCallback != nullptr) + { + mpCallback->OnSubscriptionEstablished(this); + } MoveToState(ClientState::SubscriptionActive); @@ -606,7 +602,7 @@ CHIP_ERROR ReadClient::SendSubscribeRequest(ReadPrepareParams & aReadPreparePara SubscribeRequest::Builder request; VerifyOrExit(ClientState::Initialized == mState, err = CHIP_ERROR_INCORRECT_STATE); VerifyOrExit(mpExchangeCtx == nullptr, err = CHIP_ERROR_INCORRECT_STATE); - VerifyOrExit(mpDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE); + VerifyOrExit(mpCallback != nullptr, err = CHIP_ERROR_INCORRECT_STATE); msgBuf = System::PacketBufferHandle::New(kMaxSecureSduLengthBytes); VerifyOrExit(!msgBuf.IsNull(), err = CHIP_ERROR_NO_MEMORY); diff --git a/src/app/ReadClient.h b/src/app/ReadClient.h index f70b7a4e9078bd..2b77a6194c2539 100644 --- a/src/app/ReadClient.h +++ b/src/app/ReadClient.h @@ -55,6 +55,82 @@ namespace app { class ReadClient : public Messaging::ExchangeDelegate { public: + class Callback + { + public: + virtual ~Callback() = default; + /** + * Notification that a list of events is received on the given read client. + * The ReadClient object MUST continue to exist after this call is completed. + * + * @param[in] apReadClient The read client which initialized the read transaction. + * @param[in] apEventListReader TLV reader positioned at the list that contains the events. The + * implementation of EventStreamReceived is expected to call Next() on the reader to + * advance it to the first element of the list, then process the elements from beginning to + * the end. The callee is expected to consume all events. + */ + virtual void OnEventData(const ReadClient * apReadClient, TLV::TLVReader & aEventList) {} + + /** + * OnResponse will be called when a report data response has been received and processed for the given path. + * + * The ReadClient object MUST continue to exist after this call is completed. + * + * This callback will be called when: + * - Receiving attribute data as response of Read interactions + * - Receiving attribute data as reports of subscriptions + * - Receiving attribute data as initial reports of subscriptions + * + * @param[in] apReadClient: The read client object that initiated the read or subscribe transaction. + * @param[in] aPath: The attribute path field in report response. + * @param[in] apData: The attribute data of the given path, will be a nullptr if status is not Success. + * @param[in] aStatus: Attribute-specific status, containing an InteractionModel::Status code as well as an optional + * cluster-specific status code. + */ + virtual void OnAttributeData(const ReadClient * apReadClient, const ConcreteAttributePath & aPath, TLV::TLVReader * apData, + const StatusIB & aStatus) + {} + + /** + * OnSubscriptionEstablished will be called when a subscription is established for the given subscription transaction. + * + * The ReadClient object MUST continue to exist after this call is completed. The application shall wait until it + * receives an OnDone call before it shuts down the object. + * + * @param[in] apReadClient: The read client object that initiated the read transaction. + */ + virtual void OnSubscriptionEstablished(const ReadClient * apReadClient) {} + + /** + * OnError will be called when an error occurs *after* a successful call to SendReadRequest(). The following + * errors will be delivered through this call in the aError field: + * + * - CHIP_ERROR_TIMEOUT: A response was not received within the expected response timeout. + * - CHIP_ERROR_*TLV*: A malformed, non-compliant response was received from the server. + * - CHIP_ERROR*: All other cases. + * + * The ReadClient object MUST continue to exist after this call is completed. The application shall wait until it + * receives an OnDone call before it shuts down the object. + * + * @param[in] apReadClient: The read client object that initiated the attribute read transaction. + * @param[in] aError: A system error code that conveys the overall error code. + */ + virtual void OnError(const ReadClient * apReadClient, CHIP_ERROR aError) {} + + /** + * OnDone will be called when ReadClient has finished all work and is reserved for future ReadClient ownership change. + * (#10366) Users may use this function to release their own objects related to this write interaction. + * + * This function will: + * - Always be called exactly *once* for a given WriteClient instance. + * - Be called even in error circumstances. + * - Only be called after a successful call to SendWriteRequest as been made. + * + * @param[in] apReadClient: The read client object of the terminated read transaction. + */ + virtual void OnDone(ReadClient * apReadClient) = 0; + }; + enum class InteractionType : uint8_t { Read, @@ -92,7 +168,6 @@ class ReadClient : public Messaging::ExchangeDelegate */ CHIP_ERROR SendSubscribeRequest(ReadPrepareParams & aSubscribePrepareParams); CHIP_ERROR OnUnsolicitedReportData(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload); - uint64_t GetAppIdentifier() const { return mAppIdentifier; } auto GetSubscriptionId() const { @@ -145,8 +220,7 @@ class ReadClient : public Messaging::ExchangeDelegate * @retval #CHIP_NO_ERROR On success. * */ - CHIP_ERROR Init(Messaging::ExchangeManager * apExchangeMgr, InteractionModelDelegate * apDelegate, - InteractionType aInteractionType, uint64_t aAppIdentifier); + CHIP_ERROR Init(Messaging::ExchangeManager * apExchangeMgr, Callback * apCallback, InteractionType aInteractionType); virtual ~ReadClient() = default; @@ -187,9 +261,8 @@ class ReadClient : public Messaging::ExchangeDelegate bool IsInitialReport() { return mInitialReport; } Messaging::ExchangeManager * mpExchangeMgr = nullptr; Messaging::ExchangeContext * mpExchangeCtx = nullptr; - InteractionModelDelegate * mpDelegate = nullptr; + Callback * mpCallback = nullptr; ClientState mState = ClientState::Uninitialized; - uint64_t mAppIdentifier = 0; bool mInitialReport = true; uint16_t mMinIntervalFloorSeconds = 0; uint16_t mMaxIntervalCeilingSeconds = 0; diff --git a/src/app/tests/TestReadInteraction.cpp b/src/app/tests/TestReadInteraction.cpp index a82b74f5439e7a..15faa65fa764ed 100644 --- a/src/app/tests/TestReadInteraction.cpp +++ b/src/app/tests/TestReadInteraction.cpp @@ -153,64 +153,50 @@ void GenerateSubscribeResponse(nlTestSuite * apSuite, void * apContext, chip::Sy NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); } -class MockInteractionModelApp : public chip::app::InteractionModelDelegate +class MockInteractionModelApp : public chip::app::ReadClient::Callback, public chip::app::InteractionModelDelegate { public: - CHIP_ERROR EventStreamReceived(const chip::Messaging::ExchangeContext * apExchangeContext, - chip::TLV::TLVReader * apEventListReader) override + void OnEventData(const chip::app::ReadClient * apReadClient, chip::TLV::TLVReader & apEventListReader) override { CHIP_ERROR err = CHIP_NO_ERROR; chip::TLV::TLVReader reader; int numDataElementIndex = 0; - reader.Init(*apEventListReader); + reader.Init(apEventListReader); while (CHIP_NO_ERROR == (err = reader.Next())) { uint8_t priorityLevel = 0; chip::app::EventDataElement::Parser event; - ReturnErrorOnFailure(event.Init(reader)); - ReturnErrorOnFailure(event.GetPriorityLevel(&priorityLevel)); + VerifyOrReturn(event.Init(reader) == CHIP_NO_ERROR); + VerifyOrReturn(event.GetPriorityLevel(&priorityLevel) == CHIP_NO_ERROR); if (numDataElementIndex == 0) { - VerifyOrReturnError(priorityLevel == static_cast(chip::app::PriorityLevel::Critical), - CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturn(priorityLevel == static_cast(chip::app::PriorityLevel::Critical)); } else if (numDataElementIndex == 1) { - VerifyOrReturnError(priorityLevel == static_cast(chip::app::PriorityLevel::Info), - CHIP_ERROR_INCORRECT_STATE); + VerifyOrReturn(priorityLevel == static_cast(chip::app::PriorityLevel::Info)); } ++numDataElementIndex; } if (CHIP_END_OF_TLV == err) { mGotEventResponse = true; - err = CHIP_NO_ERROR; } - return err; } - void OnReportData(const chip::app::ReadClient * apReadClient, const chip::app::ClusterInfo & aPath, - chip::TLV::TLVReader * apData, chip::Protocols::InteractionModel::Status status) override + void OnAttributeData(const chip::app::ReadClient * apReadClient, const chip::app::ConcreteAttributePath & aPath, + chip::TLV::TLVReader * apData, const chip::app::StatusIB & status) override { - if (status == chip::Protocols::InteractionModel::Status::Success) + if (status.mStatus == chip::Protocols::InteractionModel::Status::Success) { mNumAttributeResponse++; + mGotReport = true; } } - CHIP_ERROR ReportProcessed(const chip::app::ReadClient * apReadClient) override - { - mGotReport = true; - return CHIP_NO_ERROR; - } - - CHIP_ERROR ReadError(chip::app::ReadClient * apReadClient, CHIP_ERROR aError) override - { - mReadError = true; - return CHIP_NO_ERROR; - } + void OnError(const chip::app::ReadClient * apReadClient, CHIP_ERROR aError) override { mReadError = true; } - CHIP_ERROR ReadDone(chip::app::ReadClient * apReadClient) override { return CHIP_NO_ERROR; } + void OnDone(chip::app::ReadClient * apReadClient) override {} CHIP_ERROR SubscriptionEstablished(const chip::app::ReadHandler * apReadHandler) override { @@ -368,10 +354,9 @@ void TestReadInteraction::TestReadClient(nlTestSuite * apSuite, void * apContext CHIP_ERROR err = CHIP_NO_ERROR; TestContext & ctx = *static_cast(apContext); app::ReadClient readClient; - chip::app::InteractionModelDelegate delegate; + MockInteractionModelApp delegate; System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); - err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Read, - 0 /* application identifier */); + err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Read); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); ReadPrepareParams readPrepareParams(ctx.GetSessionBobToAlice()); err = readClient.SendReadRequest(readPrepareParams); @@ -394,7 +379,7 @@ void TestReadInteraction::TestReadHandler(nlTestSuite * apSuite, void * apContex System::PacketBufferHandle reportDatabuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); System::PacketBufferHandle readRequestbuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); ReadRequest::Builder readRequestBuilder; - chip::app::InteractionModelDelegate delegate; + MockInteractionModelApp delegate; auto * engine = chip::app::InteractionModelEngine::GetInstance(); err = engine->Init(&ctx.GetExchangeManager(), &delegate); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -442,7 +427,7 @@ void TestReadInteraction::TestReadClientGenerateAttributePathList(nlTestSuite * CHIP_ERROR err = CHIP_NO_ERROR; TestContext & ctx = *static_cast(apContext); app::ReadClient readClient; - chip::app::InteractionModelDelegate delegate; + MockInteractionModelApp delegate; System::PacketBufferHandle msgBuf; System::PacketBufferTLVWriter writer; ReadRequest::Builder request; @@ -452,8 +437,7 @@ void TestReadInteraction::TestReadClientGenerateAttributePathList(nlTestSuite * err = request.Init(&writer); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Read, - 0 /* application identifier */); + err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Read); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); AttributePathParams attributePathParams[2]; @@ -470,15 +454,14 @@ void TestReadInteraction::TestReadClientGenerateInvalidAttributePathList(nlTestS CHIP_ERROR err = CHIP_NO_ERROR; TestContext & ctx = *static_cast(apContext); app::ReadClient readClient; - chip::app::InteractionModelDelegate delegate; + MockInteractionModelApp delegate; System::PacketBufferHandle msgBuf; System::PacketBufferTLVWriter writer; ReadRequest::Builder request; msgBuf = System::PacketBufferHandle::New(kMaxSecureSduLengthBytes); NL_TEST_ASSERT(apSuite, !msgBuf.IsNull()); writer.Init(std::move(msgBuf)); - err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Read, - 0 /* application identifier */); + err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Read); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); err = request.Init(&writer); @@ -497,11 +480,10 @@ void TestReadInteraction::TestReadClientInvalidReport(nlTestSuite * apSuite, voi CHIP_ERROR err = CHIP_NO_ERROR; TestContext & ctx = *static_cast(apContext); app::ReadClient readClient; - chip::app::InteractionModelDelegate delegate; + MockInteractionModelApp delegate; System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); - err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Read, - 0 /* application identifier */); + err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Read); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); ReadPrepareParams readPrepareParams(ctx.GetSessionBobToAlice()); @@ -525,7 +507,7 @@ void TestReadInteraction::TestReadHandlerInvalidAttributePath(nlTestSuite * apSu System::PacketBufferHandle reportDatabuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); System::PacketBufferHandle readRequestbuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); ReadRequest::Builder readRequestBuilder; - chip::app::InteractionModelDelegate delegate; + MockInteractionModelApp delegate; auto * engine = chip::app::InteractionModelEngine::GetInstance(); err = engine->Init(&ctx.GetExchangeManager(), &delegate); @@ -570,7 +552,7 @@ void TestReadInteraction::TestReadClientGenerateOneEventPathList(nlTestSuite * a CHIP_ERROR err = CHIP_NO_ERROR; TestContext & ctx = *static_cast(apContext); app::ReadClient readClient; - chip::app::InteractionModelDelegate delegate; + MockInteractionModelApp delegate; System::PacketBufferHandle msgBuf; System::PacketBufferTLVWriter writer; ReadRequest::Builder request; @@ -580,8 +562,7 @@ void TestReadInteraction::TestReadClientGenerateOneEventPathList(nlTestSuite * a err = request.Init(&writer); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Read, - 0 /* application identifier */); + err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Read); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); chip::app::EventPathParams eventPathParams[2]; @@ -620,7 +601,7 @@ void TestReadInteraction::TestReadClientGenerateTwoEventPathList(nlTestSuite * a CHIP_ERROR err = CHIP_NO_ERROR; TestContext & ctx = *static_cast(apContext); app::ReadClient readClient; - chip::app::InteractionModelDelegate delegate; + MockInteractionModelApp delegate; System::PacketBufferHandle msgBuf; System::PacketBufferTLVWriter writer; ReadRequest::Builder request; @@ -630,8 +611,7 @@ void TestReadInteraction::TestReadClientGenerateTwoEventPathList(nlTestSuite * a err = request.Init(&writer); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); - err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Read, - 0 /* application identifier */); + err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Read); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); chip::app::EventPathParams eventPathParams[2]; @@ -719,7 +699,7 @@ void TestReadInteraction::TestReadRoundtrip(nlTestSuite * apSuite, void * apCont readPrepareParams.mEventPathParamsListSize = 2; readPrepareParams.mpAttributePathParamsList = attributePathParams; readPrepareParams.mAttributePathParamsListSize = 2; - err = chip::app::InteractionModelEngine::GetInstance()->SendReadRequest(readPrepareParams); + err = chip::app::InteractionModelEngine::GetInstance()->SendReadRequest(readPrepareParams, &delegate); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); InteractionModelEngine::GetInstance()->GetReportingEngine().Run(); @@ -762,7 +742,7 @@ void TestReadInteraction::TestReadInvalidAttributePathRoundtrip(nlTestSuite * ap ReadPrepareParams readPrepareParams(ctx.GetSessionBobToAlice()); readPrepareParams.mpAttributePathParamsList = attributePathParams; readPrepareParams.mAttributePathParamsListSize = 1; - err = chip::app::InteractionModelEngine::GetInstance()->SendReadRequest(readPrepareParams); + err = chip::app::InteractionModelEngine::GetInstance()->SendReadRequest(readPrepareParams, &delegate); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); InteractionModelEngine::GetInstance()->GetReportingEngine().Run(); @@ -780,10 +760,9 @@ void TestReadInteraction::TestProcessSubscribeResponse(nlTestSuite * apSuite, vo CHIP_ERROR err = CHIP_NO_ERROR; TestContext & ctx = *static_cast(apContext); app::ReadClient readClient; - chip::app::InteractionModelDelegate delegate; + MockInteractionModelApp delegate; System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); - err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Subscribe, - 0 /* application identifier */); + err = readClient.Init(&ctx.GetExchangeManager(), &delegate, chip::app::ReadClient::InteractionType::Subscribe); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); readClient.MoveToState(chip::app::ReadClient::ClientState::AwaitingSubscribeResponse); @@ -803,7 +782,7 @@ void TestReadInteraction::TestProcessSubscribeRequest(nlTestSuite * apSuite, voi System::PacketBufferTLVWriter writer; System::PacketBufferHandle subscribeRequestbuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize); SubscribeRequest::Builder subscribeRequestBuilder; - chip::app::InteractionModelDelegate delegate; + MockInteractionModelApp delegate; auto * engine = chip::app::InteractionModelEngine::GetInstance(); err = engine->Init(&ctx.GetExchangeManager(), &delegate); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); @@ -908,12 +887,12 @@ void TestReadInteraction::TestSubscribeRoundtrip(nlTestSuite * apSuite, void * a readPrepareParams.mMaxIntervalCeilingSeconds = 5; printf("\nSend subscribe request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId); - err = engine->SendSubscribeRequest(readPrepareParams); + err = engine->SendSubscribeRequest(readPrepareParams, &delegate); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); delegate.mNumAttributeResponse = 0; readPrepareParams.mKeepSubscriptions = false; - err = engine->SendSubscribeRequest(readPrepareParams); + err = engine->SendSubscribeRequest(readPrepareParams, &delegate); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); delegate.mGotReport = false; engine->GetReportingEngine().Run(); @@ -1012,7 +991,6 @@ void TestReadInteraction::TestSubscribeRoundtrip(nlTestSuite * apSuite, void * a delegate.mGotReport = false; delegate.mNumAttributeResponse = 0; engine->GetReportingEngine().Run(); - NL_TEST_ASSERT(apSuite, delegate.mGotReport); NL_TEST_ASSERT(apSuite, delegate.mNumAttributeResponse == 0); // Test multiple subscriptipn @@ -1032,7 +1010,7 @@ void TestReadInteraction::TestSubscribeRoundtrip(nlTestSuite * apSuite, void * a readPrepareParams1.mMaxIntervalCeilingSeconds = 5; printf("\nSend another subscribe request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId); - err = engine->SendSubscribeRequest(readPrepareParams1); + err = engine->SendSubscribeRequest(readPrepareParams1, &delegate); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); engine->GetReportingEngine().Run(); NL_TEST_ASSERT(apSuite, delegate.mGotReport); @@ -1093,7 +1071,7 @@ void TestReadInteraction::TestSubscribeInvalidAttributePathRoundtrip(nlTestSuite readPrepareParams.mMaxIntervalCeilingSeconds = 5; printf("\nSend subscribe request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId); - err = chip::app::InteractionModelEngine::GetInstance()->SendSubscribeRequest(readPrepareParams); + err = chip::app::InteractionModelEngine::GetInstance()->SendSubscribeRequest(readPrepareParams, &delegate); NL_TEST_ASSERT(apSuite, err == CHIP_NO_ERROR); delegate.mNumAttributeResponse = 0; InteractionModelEngine::GetInstance()->GetReportingEngine().Run(); diff --git a/src/app/tests/integration/chip_im_initiator.cpp b/src/app/tests/integration/chip_im_initiator.cpp index 20a28a6cd7ffe2..ce03af677a29e4 100644 --- a/src/app/tests/integration/chip_im_initiator.cpp +++ b/src/app/tests/integration/chip_im_initiator.cpp @@ -126,15 +126,12 @@ void HandleSubscribeReportComplete() class MockInteractionModelApp : public chip::app::InteractionModelDelegate, public ::chip::app::CommandSender::Callback, - public ::chip::app::WriteClient::Callback + public ::chip::app::WriteClient::Callback, + public ::chip::app::ReadClient::Callback { public: - CHIP_ERROR EventStreamReceived(const chip::Messaging::ExchangeContext * apExchangeContext, - chip::TLV::TLVReader * apEventListReader) override - { - return CHIP_NO_ERROR; - } - CHIP_ERROR ReportProcessed(const chip::app::ReadClient * apReadClient) override + void OnEventData(const chip::app::ReadClient * apReadClient, chip::TLV::TLVReader & apEventListReader) override {} + void OnSubscriptionEstablished(const chip::app::ReadClient * apReadClient) override { if (apReadClient->IsSubscriptionType()) { @@ -144,22 +141,21 @@ class MockInteractionModelApp : public chip::app::InteractionModelDelegate, HandleSubscribeReportComplete(); } } - - return CHIP_NO_ERROR; } + void OnAttributeData(const chip::app::ReadClient * apReadClient, const chip::app::ConcreteAttributePath & aPath, + chip::TLV::TLVReader * aData, const chip::app::StatusIB & status) override + {} - CHIP_ERROR ReadError(chip::app::ReadClient * apReadClient, CHIP_ERROR aError) override + void OnError(const chip::app::ReadClient * apReadClient, CHIP_ERROR aError) override { printf("ReadError with err %" CHIP_ERROR_FORMAT, aError.Format()); - return CHIP_NO_ERROR; } - CHIP_ERROR ReadDone(chip::app::ReadClient * apReadClient) override + void OnDone(chip::app::ReadClient * apReadClient) override { if (!apReadClient->IsSubscriptionType()) { HandleReadComplete(); } - return CHIP_NO_ERROR; } void OnResponse(chip::app::CommandSender * apCommandSender, const chip::app::ConcreteCommandPath & aPath, @@ -320,7 +316,7 @@ CHIP_ERROR SendReadRequest() readPrepareParams.mAttributePathParamsListSize = 1; readPrepareParams.mpEventPathParamsList = eventPathParams; readPrepareParams.mEventPathParamsListSize = 2; - err = chip::app::InteractionModelEngine::GetInstance()->SendReadRequest(readPrepareParams); + err = chip::app::InteractionModelEngine::GetInstance()->SendReadRequest(readPrepareParams, &gMockDelegate); SuccessOrExit(err); exit: @@ -405,7 +401,7 @@ CHIP_ERROR SendSubscribeRequest() readPrepareParams.mMaxIntervalCeilingSeconds = 5; printf("\nSend subscribe request message to Node: %" PRIu64 "\n", chip::kTestDeviceNodeId); - err = chip::app::InteractionModelEngine::GetInstance()->SendSubscribeRequest(readPrepareParams); + err = chip::app::InteractionModelEngine::GetInstance()->SendSubscribeRequest(readPrepareParams, &gMockDelegate); SuccessOrExit(err); gSubCount++; diff --git a/src/app/util/im-client-callbacks.cpp b/src/app/util/im-client-callbacks.cpp index c60631f496907c..7d3a83cdb952c5 100644 --- a/src/app/util/im-client-callbacks.cpp +++ b/src/app/util/im-client-callbacks.cpp @@ -362,28 +362,32 @@ bool IMWriteResponseCallback(const chip::app::WriteClient * writeClient, chip::P return true; } -bool IMReadReportAttributesResponseCallback(const app::ReadClient * apReadClient, const app::ClusterInfo & aPath, +bool IMReadReportAttributesResponseCallback(const app::ReadClient * apReadClient, const app::ConcreteAttributePath * aPath, TLV::TLVReader * apData, Protocols::InteractionModel::Status status) { ChipLogProgress(Zcl, "ReadAttributesResponse:"); - ChipLogProgress(Zcl, " ClusterId: " ChipLogFormatMEI, ChipLogValueMEI(aPath.mClusterId)); + if (aPath != nullptr) + { + ChipLogProgress(Zcl, " ClusterId: " ChipLogFormatMEI, ChipLogValueMEI(aPath->mClusterId)); + } Callback::Cancelable * onSuccessCallback = nullptr; Callback::Cancelable * onFailureCallback = nullptr; app::TLVDataFilter tlvFilter = nullptr; - NodeId sourceId = apReadClient->GetPeerNodeId(); // In CHIPClusters.cpp, we are using sequenceNumber as application identifier. - uint8_t sequenceNumber = static_cast(apReadClient->GetAppIdentifier()); - CHIP_ERROR err = CHIP_NO_ERROR; if (apReadClient->IsSubscriptionType()) { - err = gCallbacks.GetReportCallback(sourceId, aPath.mEndpointId, aPath.mClusterId, aPath.mFieldId, &onSuccessCallback, - &tlvFilter); + if (aPath != nullptr) + { + err = gCallbacks.GetReportCallback(apReadClient->GetPeerNodeId(), aPath->mEndpointId, aPath->mClusterId, + aPath->mAttributeId, &onSuccessCallback, &tlvFilter); + } } else { - err = gCallbacks.GetResponseCallback(sourceId, sequenceNumber, &onSuccessCallback, &onFailureCallback, &tlvFilter); + err = gCallbacks.GetResponseCallback(reinterpret_cast(apReadClient), 0, &onSuccessCallback, &onFailureCallback, + &tlvFilter); } if (CHIP_NO_ERROR != err) @@ -405,7 +409,10 @@ bool IMReadReportAttributesResponseCallback(const app::ReadClient * apReadClient return true; } - ChipLogProgress(Zcl, " attributeId: " ChipLogFormatMEI, ChipLogValueMEI(aPath.mFieldId)); + if (aPath != nullptr) + { + ChipLogProgress(Zcl, " attributeId: " ChipLogFormatMEI, ChipLogValueMEI(aPath->mAttributeId)); + } LogIMStatus(status); if (status == Protocols::InteractionModel::Status::Success && apData != nullptr) @@ -436,17 +443,13 @@ bool IMSubscribeResponseCallback(const chip::app::ReadClient * apSubscribeClient { ChipLogProgress(Zcl, " SubscriptionId: "); } - ChipLogProgress(Zcl, " ApplicationIdentifier: %" PRIx64, apSubscribeClient->GetAppIdentifier()); LogStatus(status); // In CHIPClusters.cpp, we are using sequenceNumber as application identifier. - uint8_t sequenceNumber = static_cast(apSubscribeClient->GetAppIdentifier()); - CHIP_ERROR err = CHIP_NO_ERROR; Callback::Cancelable * onSuccessCallback = nullptr; Callback::Cancelable * onFailureCallback = nullptr; - err = - gCallbacks.GetResponseCallback(apSubscribeClient->GetPeerNodeId(), sequenceNumber, &onSuccessCallback, &onFailureCallback); + err = gCallbacks.GetResponseCallback(reinterpret_cast(apSubscribeClient), 0, &onSuccessCallback, &onFailureCallback); if (CHIP_NO_ERROR != err) { diff --git a/src/app/util/im-client-callbacks.h b/src/app/util/im-client-callbacks.h index 5b241db440b18e..c06e906744b15d 100644 --- a/src/app/util/im-client-callbacks.h +++ b/src/app/util/im-client-callbacks.h @@ -29,8 +29,9 @@ // instead of IM status code. // #6308 should handle IM error code on the application side, either modify this function or remove this. bool IMDefaultResponseCallback(const chip::app::Command * commandObj, EmberAfStatus status); -bool IMReadReportAttributesResponseCallback(const chip::app::ReadClient * apReadClient, const chip::app::ClusterInfo & aPath, - chip::TLV::TLVReader * apData, chip::Protocols::InteractionModel::Status status); +bool IMReadReportAttributesResponseCallback(const chip::app::ReadClient * apReadClient, + const chip::app::ConcreteAttributePath * aPath, chip::TLV::TLVReader * apData, + chip::Protocols::InteractionModel::Status status); bool IMWriteResponseCallback(const chip::app::WriteClient * writeClient, chip::Protocols::InteractionModel::Status status); bool IMSubscribeResponseCallback(const chip::app::ReadClient * apSubscribeClient, EmberAfStatus status); void LogStatus(uint8_t status); diff --git a/src/controller/CHIPDevice.cpp b/src/controller/CHIPDevice.cpp index 1fd3fa66204e1b..910d40f971e6e4 100644 --- a/src/controller/CHIPDevice.cpp +++ b/src/controller/CHIPDevice.cpp @@ -716,34 +716,23 @@ CHIP_ERROR Device::EstablishConnectivity(Callback::Callback * return CHIP_NO_ERROR; } -void Device::AddResponseHandler(uint8_t seqNum, Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, - app::TLVDataFilter tlvDataFilter) -{ - mCallbacksMgr.AddResponseCallback(mDeviceId, seqNum, onSuccessCallback, onFailureCallback, tlvDataFilter); -} - -void Device::CancelResponseHandler(uint8_t seqNum) -{ - mCallbacksMgr.CancelResponseCallback(mDeviceId, seqNum); -} - void Device::AddIMResponseHandler(void * commandObj, Callback::Cancelable * onSuccessCallback, - Callback::Cancelable * onFailureCallback) + Callback::Cancelable * onFailureCallback, app::TLVDataFilter tlvDataFilter) { - // We are using the pointer to command sender object as the identifier of command transactions. This makes sense as long as - // there are only one active command transaction on one command sender object. This is a bit tricky, we try to assume that - // chip::NodeId is uint64_t so the pointer can be used as a NodeId for CallbackMgr. + // Interaction model uses the object instead of a sequence number as the identifier of transactions. + // Since the objects can be identified by its pointer which fits into a uint64 value (the type of NodeId), we use it for the + // "node id" field in callback manager. static_assert(std::is_same::value, "chip::NodeId is not uint64_t"); chip::NodeId transactionId = reinterpret_cast(commandObj); mCallbacksMgr.AddResponseCallback(transactionId, 0 /* seqNum, always 0 for IM before #6559 */, onSuccessCallback, - onFailureCallback); + onFailureCallback, tlvDataFilter); } void Device::CancelIMResponseHandler(void * commandObj) { - // We are using the pointer to command sender object as the identifier of command transactions. This makes sense as long as - // there are only one active command transaction on one command sender object. This is a bit tricky, we try to assume that - // chip::NodeId is uint64_t so the pointer can be used as a NodeId for CallbackMgr. + // Interaction model uses the object instead of a sequence number as the identifier of transactions. + // Since the objects can be identified by its pointer which fits into a uint64 value (the type of NodeId), we use it for the + // "node id" field in callback manager. static_assert(std::is_same::value, "chip::NodeId is not uint64_t"); chip::NodeId transactionId = reinterpret_cast(commandObj); mCallbacksMgr.CancelResponseCallback(transactionId, 0 /* seqNum, always 0 for IM before #6559 */); @@ -759,27 +748,30 @@ CHIP_ERROR Device::SendReadAttributeRequest(app::AttributePathParams aPath, Call Callback::Cancelable * onFailureCallback, app::TLVDataFilter aTlvDataFilter) { bool loadedSecureSession = false; - uint8_t seqNum = GetNextSequenceNumber(); aPath.mNodeId = GetDeviceId(); ReturnErrorOnFailure(LoadSecureSessionParametersIfNeeded(loadedSecureSession)); VerifyOrReturnError(mState == ConnectionState::SecureConnected, CHIP_ERROR_INCORRECT_STATE); VerifyOrReturnError(GetSecureSession().HasValue(), CHIP_ERROR_INCORRECT_STATE); + app::ReadClient * readClient = nullptr; + ReturnErrorOnFailure(chip::app::InteractionModelEngine::GetInstance()->NewReadClient( + &readClient, app::ReadClient::InteractionType::Read, mpIMDelegate)); + if (onSuccessCallback != nullptr || onFailureCallback != nullptr) { - AddResponseHandler(seqNum, onSuccessCallback, onFailureCallback, aTlvDataFilter); + AddIMResponseHandler(readClient, onSuccessCallback, onFailureCallback, aTlvDataFilter); } // The application context is used to identify different requests from client application the type of it is intptr_t, here we // use the seqNum. chip::app::ReadPrepareParams readPrepareParams(mSecureSession.Value()); readPrepareParams.mpAttributePathParamsList = &aPath; readPrepareParams.mAttributePathParamsListSize = 1; - CHIP_ERROR err = - chip::app::InteractionModelEngine::GetInstance()->SendReadRequest(readPrepareParams, seqNum /* application context */); + + CHIP_ERROR err = readClient->SendReadRequest(readPrepareParams); if (err != CHIP_NO_ERROR) { - CancelResponseHandler(seqNum); + CancelIMResponseHandler(readClient); } return err; } @@ -789,12 +781,15 @@ CHIP_ERROR Device::SendSubscribeAttributeRequest(app::AttributePathParams aPath, Callback::Cancelable * onFailureCallback) { bool loadedSecureSession = false; - uint8_t seqNum = GetNextSequenceNumber(); aPath.mNodeId = GetDeviceId(); ReturnErrorOnFailure(LoadSecureSessionParametersIfNeeded(loadedSecureSession)); - app::AttributePathParams * path = mpIMDelegate->AllocateAttributePathParam(1, seqNum); + app::ReadClient * readClient = nullptr; + ReturnErrorOnFailure(chip::app::InteractionModelEngine::GetInstance()->NewReadClient( + &readClient, app::ReadClient::InteractionType::Subscribe, mpIMDelegate)); + + app::AttributePathParams * path = mpIMDelegate->AllocateAttributePathParam(1, reinterpret_cast(readClient)); VerifyOrReturnError(path != nullptr, CHIP_ERROR_NO_MEMORY); @@ -810,17 +805,17 @@ CHIP_ERROR Device::SendSubscribeAttributeRequest(app::AttributePathParams aPath, params.mMaxIntervalCeilingSeconds = mMaxIntervalCeilingSeconds; params.mKeepSubscriptions = false; - CHIP_ERROR err = - chip::app::InteractionModelEngine::GetInstance()->SendSubscribeRequest(params, seqNum /* application context */); + CHIP_ERROR err = readClient->SendSubscribeRequest(params); if (err != CHIP_NO_ERROR) { - mpIMDelegate->FreeAttributePathParam(seqNum); + mpIMDelegate->FreeAttributePathParam(reinterpret_cast(readClient)); + readClient->Shutdown(); return err; } if (onSuccessCallback != nullptr || onFailureCallback != nullptr) { - AddResponseHandler(seqNum, onSuccessCallback, onFailureCallback); + AddIMResponseHandler(readClient, onSuccessCallback, onFailureCallback); } return CHIP_NO_ERROR; } diff --git a/src/controller/CHIPDevice.h b/src/controller/CHIPDevice.h index d98ae89f63d3d1..f1f0fc327a8db9 100644 --- a/src/controller/CHIPDevice.h +++ b/src/controller/CHIPDevice.h @@ -386,18 +386,11 @@ class DLL_EXPORT Device : public Messaging::ExchangeDelegate, public SessionEsta PASESessionSerializable & GetPairing() { return mPairing; } uint8_t GetNextSequenceNumber() { return mSequenceNumber++; }; - void AddResponseHandler(uint8_t seqNum, Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, - app::TLVDataFilter tlvDataFilter = nullptr); - void CancelResponseHandler(uint8_t seqNum); void AddReportHandler(EndpointId endpoint, ClusterId cluster, AttributeId attribute, Callback::Cancelable * onReportCallback, app::TLVDataFilter tlvDataFilter); - - // This two functions are pretty tricky, it is used to bridge the response, we need to implement interaction model delegate - // on the app side instead of register callbacks here. The IM delegate can provide more infomation then callback and it is - // type-safe. - // TODO: Implement interaction model delegate in the application. - void AddIMResponseHandler(void * commandObj, Callback::Cancelable * onSuccessCallback, - Callback::Cancelable * onFailureCallback); + // Interaction model uses the object and callback interface instead of sequence number to mark different transactions. + void AddIMResponseHandler(void * commandObj, Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback, + app::TLVDataFilter tlvDataFilter = nullptr); void CancelIMResponseHandler(void * commandObj); void OperationalCertProvisioned(); diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 68ae2034805474..89d3baa5c66729 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -1642,28 +1642,31 @@ void DeviceControllerInteractionModelDelegate::OnDone(app::CommandSender * apCom return chip::Platform::Delete(apCommandSender); } -void DeviceControllerInteractionModelDelegate::OnReportData(const app::ReadClient * apReadClient, const app::ClusterInfo & aPath, - TLV::TLVReader * apData, Protocols::InteractionModel::Status status) +void DeviceControllerInteractionModelDelegate::OnAttributeData(const app::ReadClient * apReadClient, + const app::ConcreteAttributePath & aPath, TLV::TLVReader * apData, + const app::StatusIB & aStatus) { - IMReadReportAttributesResponseCallback(apReadClient, aPath, apData, status); + IMReadReportAttributesResponseCallback(apReadClient, &aPath, apData, aStatus.mStatus); } -CHIP_ERROR DeviceControllerInteractionModelDelegate::ReadError(app::ReadClient * apReadClient, CHIP_ERROR aError) +void DeviceControllerInteractionModelDelegate::OnSubscriptionEstablished(const app::ReadClient * apReadClient) +{ + IMSubscribeResponseCallback(apReadClient, EMBER_ZCL_STATUS_SUCCESS); +} + +void DeviceControllerInteractionModelDelegate::OnError(const app::ReadClient * apReadClient, CHIP_ERROR aError) { app::ClusterInfo path; path.mNodeId = apReadClient->GetPeerNodeId(); - IMReadReportAttributesResponseCallback(apReadClient, path, nullptr, Protocols::InteractionModel::Status::Failure); - return CHIP_NO_ERROR; + IMReadReportAttributesResponseCallback(apReadClient, nullptr, nullptr, Protocols::InteractionModel::Status::Failure); } -CHIP_ERROR DeviceControllerInteractionModelDelegate::ReadDone(app::ReadClient * apReadClient) +void DeviceControllerInteractionModelDelegate::OnDone(app::ReadClient * apReadClient) { - // Release the object for subscription if (apReadClient->IsSubscriptionType()) { - FreeAttributePathParam(apReadClient->GetAppIdentifier()); + this->FreeAttributePathParam(reinterpret_cast(apReadClient)); } - return CHIP_NO_ERROR; } void DeviceControllerInteractionModelDelegate::OnResponse(const app::WriteClient * apWriteClient, @@ -1678,15 +1681,6 @@ void DeviceControllerInteractionModelDelegate::OnError(const app::WriteClient * void DeviceControllerInteractionModelDelegate::OnDone(app::WriteClient * apWriteClient) {} -CHIP_ERROR DeviceControllerInteractionModelDelegate::SubscribeResponseProcessed(const app::ReadClient * apSubscribeClient) -{ -#if !CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE // temporary - until example app clusters are updated (Issue 8347) - // When WriteResponseError occurred, it means we failed to receive the response from server. - IMSubscribeResponseCallback(apSubscribeClient, EMBER_ZCL_STATUS_SUCCESS); -#endif - return CHIP_NO_ERROR; -} - void BasicSuccess(void * context, uint16_t val) { ChipLogProgress(Controller, "Received success response 0x%x\n", val); diff --git a/src/controller/DeviceControllerInteractionModelDelegate.h b/src/controller/DeviceControllerInteractionModelDelegate.h index 8e0b7afe72098e..929d8eddfe3162 100644 --- a/src/controller/DeviceControllerInteractionModelDelegate.h +++ b/src/controller/DeviceControllerInteractionModelDelegate.h @@ -15,9 +15,10 @@ namespace Controller { * * TODO:(#8967) Implementation of CommandSender::Callback should be removed after switching to ClusterObjects. */ -class DeviceControllerInteractionModelDelegate : public chip::app::InteractionModelDelegate, +class DeviceControllerInteractionModelDelegate : public chip::app::ReadClient::Callback, public chip::app::CommandSender::Callback, - public chip::app::WriteClient::Callback + public chip::app::WriteClient::Callback, + public chip::app::InteractionModelDelegate { public: void OnResponse(app::CommandSender * apCommandSender, const app::ConcreteCommandPath & aPath, @@ -31,13 +32,12 @@ class DeviceControllerInteractionModelDelegate : public chip::app::InteractionMo void OnError(const app::WriteClient * apWriteClient, CHIP_ERROR aError) override; void OnDone(app::WriteClient * apWriteClient) override; - void OnReportData(const app::ReadClient * apReadClient, const app::ClusterInfo & aPath, TLV::TLVReader * apData, - Protocols::InteractionModel::Status status) override; - CHIP_ERROR ReadError(app::ReadClient * apReadClient, CHIP_ERROR aError) override; - - CHIP_ERROR SubscribeResponseProcessed(const app::ReadClient * apSubscribeClient) override; - - CHIP_ERROR ReadDone(app::ReadClient * apReadClient) override; + void OnEventData(const app::ReadClient * apReadClient, TLV::TLVReader & aEventList) override {} + void OnAttributeData(const app::ReadClient * apReadClient, const app::ConcreteAttributePath & aPath, TLV::TLVReader * apData, + const app::StatusIB & aStatus) override; + void OnSubscriptionEstablished(const app::ReadClient * apReadClient) override; + void OnError(const app::ReadClient * apReadClient, CHIP_ERROR aError) override; + void OnDone(app::ReadClient * apReadClient) override; // TODO: FreeAttributePathParam and AllocateAttributePathParam are used by CHIPDevice.cpp for getting a long-live attribute path // object. diff --git a/src/controller/ReadInteraction.h b/src/controller/ReadInteraction.h index c9def715f14501..5be23d84e864f7 100644 --- a/src/controller/ReadInteraction.h +++ b/src/controller/ReadInteraction.h @@ -57,7 +57,7 @@ CHIP_ERROR ReadAttribute(Messaging::ExchangeManager * aExchangeMgr, const Sessio auto callback = chip::Platform::MakeUnique>(onSuccessCb, onErrorCb, onDone); VerifyOrReturnError(callback != nullptr, CHIP_ERROR_NO_MEMORY); - ReturnErrorOnFailure(engine->NewReadClient(&readClient, app::ReadClient::InteractionType::Read, 0, callback.get())); + ReturnErrorOnFailure(engine->NewReadClient(&readClient, app::ReadClient::InteractionType::Read, callback.get())); err = readClient->SendReadRequest(readParams); if (err != CHIP_NO_ERROR) diff --git a/src/controller/TypedReadCallback.h b/src/controller/TypedReadCallback.h index 3464374f4ae700..3a8d4a7ef36411 100644 --- a/src/controller/TypedReadCallback.h +++ b/src/controller/TypedReadCallback.h @@ -36,7 +36,7 @@ namespace Controller { * cluster object. */ template -class TypedReadCallback final : public app::InteractionModelDelegate +class TypedReadCallback final : public app::ReadClient::Callback { public: using OnSuccessCallbackType = @@ -50,22 +50,22 @@ class TypedReadCallback final : public app::InteractionModelDelegate {} private: - void OnReportData(const app::ReadClient * apReadClient, const app::ClusterInfo & aPath, TLV::TLVReader * apData, - Protocols::InteractionModel::Status status) override + void OnAttributeData(const app::ReadClient * apReadClient, const app::ConcreteAttributePath & aPath, TLV::TLVReader * apData, + const app::StatusIB & status) override { - CHIP_ERROR err = CHIP_NO_ERROR; - app::ConcreteAttributePath attributePath = { aPath.mEndpointId, aPath.mClusterId, aPath.mFieldId }; + CHIP_ERROR err = CHIP_NO_ERROR; typename AttributeTypeInfo::DecodableType value; - VerifyOrExit(status == Protocols::InteractionModel::Status::Success, err = CHIP_ERROR_IM_STATUS_CODE_RECEIVED); - VerifyOrExit(aPath.mClusterId == AttributeTypeInfo::GetClusterId() && aPath.mFieldId == AttributeTypeInfo::GetAttributeId(), + VerifyOrExit(status.mStatus == Protocols::InteractionModel::Status::Success, err = CHIP_ERROR_IM_STATUS_CODE_RECEIVED); + VerifyOrExit(aPath.mClusterId == AttributeTypeInfo::GetClusterId() && + aPath.mAttributeId == AttributeTypeInfo::GetAttributeId(), CHIP_ERROR_SCHEMA_MISMATCH); VerifyOrExit(apData != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); err = app::DataModel::Decode(*apData, value); SuccessOrExit(err); - mOnSuccess(attributePath, value); + mOnSuccess(aPath, value); exit: if (err != CHIP_NO_ERROR) @@ -73,27 +73,22 @@ class TypedReadCallback final : public app::InteractionModelDelegate // // Override status to indicate an error if something bad happened above. // - if (status == Protocols::InteractionModel::Status::Success) + Protocols::InteractionModel::Status imStatus = status.mStatus; + if (status.mStatus == Protocols::InteractionModel::Status::Success) { - status = Protocols::InteractionModel::Status::Failure; + imStatus = Protocols::InteractionModel::Status::Failure; } - mOnError(&attributePath, status, err); + mOnError(&aPath, imStatus, err); } } - CHIP_ERROR ReadError(app::ReadClient * apReadClient, CHIP_ERROR aError) override + void OnError(const app::ReadClient * apReadClient, CHIP_ERROR aError) override { mOnError(nullptr, Protocols::InteractionModel::Status::Failure, aError); - mOnDone(apReadClient, this); - return CHIP_NO_ERROR; } - CHIP_ERROR ReadDone(app::ReadClient * apReadClient) override - { - mOnDone(apReadClient, this); - return CHIP_NO_ERROR; - } + void OnDone(app::ReadClient * apReadClient) override { mOnDone(apReadClient, this); } OnSuccessCallbackType mOnSuccess; OnErrorCallbackType mOnError; diff --git a/src/controller/python/chip/interaction_model/Delegate.cpp b/src/controller/python/chip/interaction_model/Delegate.cpp index 6d127373b597bb..944fbcf3889522 100644 --- a/src/controller/python/chip/interaction_model/Delegate.cpp +++ b/src/controller/python/chip/interaction_model/Delegate.cpp @@ -80,8 +80,8 @@ void PythonInteractionModelDelegate::OnError(const app::CommandSender * apComman DeviceControllerInteractionModelDelegate::OnError(apCommandSender, aStatus, aError); } -void PythonInteractionModelDelegate::OnReportData(const app::ReadClient * apReadClient, const app::ClusterInfo & aPath, - TLV::TLVReader * apData, Protocols::InteractionModel::Status status) +void PythonInteractionModelDelegate::OnAttributeData(const app::ReadClient * apReadClient, const app::ConcreteAttributePath & aPath, + TLV::TLVReader * apData, const app::StatusIB & status) { if (onReportDataFunct != nullptr) { @@ -102,10 +102,10 @@ void PythonInteractionModelDelegate::OnReportData(const app::ReadClient * apRead } if (CHIP_NO_ERROR == err) { - AttributePath path{ .endpointId = aPath.mEndpointId, .clusterId = aPath.mClusterId, .fieldId = aPath.mFieldId }; - onReportDataFunct(apReadClient->GetPeerNodeId(), apReadClient->GetAppIdentifier(), + AttributePath path{ .endpointId = aPath.mEndpointId, .clusterId = aPath.mClusterId, .fieldId = aPath.mAttributeId }; + onReportDataFunct(apReadClient->GetPeerNodeId(), 0, /* TODO: Use real SubscriptionId */ apReadClient->IsSubscriptionType() ? 1 : 0, &path, sizeof(path), - writerBuffer, writer.GetLengthWritten(), to_underlying(status)); + writerBuffer, writer.GetLengthWritten(), to_underlying(status.mStatus)); } else { @@ -114,7 +114,7 @@ void PythonInteractionModelDelegate::OnReportData(const app::ReadClient * apRead ChipLogError(Controller, "Cannot pass TLV data to python: failed to copy TLV: %s", ErrorStr(err)); } } - DeviceControllerInteractionModelDelegate::OnReportData(apReadClient, aPath, apData, status); + DeviceControllerInteractionModelDelegate::OnAttributeData(apReadClient, aPath, apData, status); } void pychip_InteractionModelDelegate_SetCommandResponseStatusCallback( diff --git a/src/controller/python/chip/interaction_model/Delegate.h b/src/controller/python/chip/interaction_model/Delegate.h index a55ddbf2222ebf..e2cb2f0d817219 100644 --- a/src/controller/python/chip/interaction_model/Delegate.h +++ b/src/controller/python/chip/interaction_model/Delegate.h @@ -101,8 +101,8 @@ class PythonInteractionModelDelegate : public chip::Controller::DeviceController TLV::TLVReader * aData) override; void OnError(const app::CommandSender * apCommandSender, const app::StatusIB & aStatus, CHIP_ERROR aError) override; - void OnReportData(const app::ReadClient * apReadClient, const app::ClusterInfo & aPath, TLV::TLVReader * apData, - Protocols::InteractionModel::Status status) override; + void OnAttributeData(const app::ReadClient * apReadClient, const app::ConcreteAttributePath & aPath, TLV::TLVReader * apData, + const app::StatusIB & status) override; static PythonInteractionModelDelegate & Instance(); diff --git a/src/controller/tests/data_model/TestRead.cpp b/src/controller/tests/data_model/TestRead.cpp index bd18ef6c87fea1..96730b9c30b7c2 100644 --- a/src/controller/tests/data_model/TestRead.cpp +++ b/src/controller/tests/data_model/TestRead.cpp @@ -138,8 +138,7 @@ void TestReadInteraction::TestDataResponse(nlTestSuite * apSuite, void * apConte // Passing of stack variables by reference is only safe because of synchronous completion of the interaction. Otherwise, it's // not safe to do so. - auto onFailureCb = [&onFailureCbInvoked](const app::ConcreteAttributePath * attributePath, - Protocols::InteractionModel::Status aIMStatus, + auto onFailureCb = [&onFailureCbInvoked](const app::ConcreteAttributePath * attributePath, app::StatusIB aIMStatus, CHIP_ERROR aError) { onFailureCbInvoked = true; }; chip::Controller::ReadAttribute(