3 * Copyright (c) 2021 Project CHIP Authors
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * This file defines the initiator side of a CHIP Read Interaction.
25 #include <app/InteractionModelEngine.h>
26 #include <app/ReadClient.h>
31 CHIP_ERROR ReadClient::Init(Messaging::ExchangeManager * apExchangeMgr, InteractionModelDelegate * apDelegate)
33 CHIP_ERROR err = CHIP_NO_ERROR;
34 // Error if already initialized.
35 VerifyOrExit(apExchangeMgr != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
36 VerifyOrExit(mpExchangeMgr == nullptr, err = CHIP_ERROR_INCORRECT_STATE);
37 VerifyOrExit(mpExchangeCtx == nullptr, err = CHIP_ERROR_INCORRECT_STATE);
39 mpExchangeMgr = apExchangeMgr;
40 mpExchangeCtx = nullptr;
41 mpDelegate = apDelegate;
42 mState = ClientState::Initialized;
45 ChipLogFunctError(err);
49 void ReadClient::Shutdown()
51 ClearExistingExchangeContext();
52 mpExchangeMgr = nullptr;
54 MoveToState(ClientState::Uninitialized);
57 const char * ReadClient::GetStateStr() const
59 #if CHIP_DETAIL_LOGGING
62 case ClientState::Uninitialized:
64 case ClientState::Initialized:
66 case ClientState::AwaitingResponse:
67 return "AwaitingResponse";
69 #endif // CHIP_DETAIL_LOGGING
73 void ReadClient::MoveToState(const ClientState aTargetState)
75 mState = aTargetState;
76 ChipLogDetail(DataManagement, "Client[%u] moving to [%s]", InteractionModelEngine::GetInstance()->GetReadClientArrayIndex(this),
80 CHIP_ERROR ReadClient::SendReadRequest(NodeId aNodeId, Transport::AdminId aAdminId, EventPathParams * apEventPathParamsList,
81 size_t aEventPathParamsListSize)
83 CHIP_ERROR err = CHIP_NO_ERROR;
84 System::PacketBufferHandle msgBuf;
85 ChipLogDetail(DataManagement, "%s: Client[%u] [%5.5s]", __func__,
86 InteractionModelEngine::GetInstance()->GetReadClientArrayIndex(this), GetStateStr());
87 VerifyOrExit(ClientState::Initialized == mState, err = CHIP_ERROR_INCORRECT_STATE);
88 VerifyOrExit(mpDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
89 VerifyOrExit(mpExchangeCtx == nullptr, err = CHIP_ERROR_INCORRECT_STATE);
92 System::PacketBufferTLVWriter writer;
93 ReadRequest::Builder request;
95 msgBuf = System::PacketBufferHandle::New(kMaxSecureSduLengthBytes);
96 VerifyOrExit(!msgBuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
98 writer.Init(std::move(msgBuf));
100 err = request.Init(&writer);
103 if (aEventPathParamsListSize != 0 && apEventPathParamsList != nullptr)
105 // TODO: fill to construct event paths
107 request.EndOfReadRequest();
108 SuccessOrExit(request.GetError());
110 err = writer.Finalize(&msgBuf);
114 mpExchangeCtx = mpExchangeMgr->NewContext({ aNodeId, 0, aAdminId }, this);
115 VerifyOrExit(mpExchangeCtx != nullptr, err = CHIP_ERROR_NO_MEMORY);
116 mpExchangeCtx->SetResponseTimeout(kImMessageTimeoutMsec);
118 err = mpExchangeCtx->SendMessage(Protocols::InteractionModel::MsgType::ReadRequest, std::move(msgBuf),
119 Messaging::SendFlags(Messaging::SendMessageFlags::kExpectResponse));
121 MoveToState(ClientState::AwaitingResponse);
124 ChipLogFunctError(err);
128 void ReadClient::OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PacketHeader & aPacketHeader,
129 const PayloadHeader & aPayloadHeader, System::PacketBufferHandle aPayload)
131 CHIP_ERROR err = CHIP_NO_ERROR;
132 VerifyOrExit(aPayloadHeader.HasMessageType(Protocols::InteractionModel::MsgType::ReportData),
133 err = CHIP_ERROR_INVALID_MESSAGE_TYPE);
134 VerifyOrExit(apExchangeContext == mpExchangeCtx, err = CHIP_ERROR_INCORRECT_STATE);
135 err = ProcessReportData(std::move(aPayload));
138 ChipLogFunctError(err);
139 if (err != CHIP_NO_ERROR && mpDelegate != nullptr)
141 mpDelegate->ReportError(this, err);
143 ClearExistingExchangeContext();
144 MoveToState(ClientState::Initialized);
148 CHIP_ERROR ReadClient::ClearExistingExchangeContext()
150 if (mpExchangeCtx != nullptr)
152 mpExchangeCtx->Abort();
153 mpExchangeCtx = nullptr;
156 return CHIP_NO_ERROR;
159 CHIP_ERROR ReadClient::ProcessReportData(System::PacketBufferHandle aPayload)
161 CHIP_ERROR err = CHIP_NO_ERROR;
162 ReportData::Parser report;
164 bool isEventListPresent = false;
165 bool suppressResponse = false;
166 bool moreChunkedMessages = false;
168 System::PacketBufferTLVReader reader;
170 reader.Init(std::move(aPayload));
173 err = report.Init(reader);
176 err = report.CheckSchemaValidity();
179 err = report.GetSuppressResponse(&suppressResponse);
180 if (CHIP_END_OF_TLV == err)
186 err = report.GetMoreChunkedMessages(&moreChunkedMessages);
187 if (CHIP_END_OF_TLV == err)
194 EventList::Parser eventList;
196 err = report.GetEventDataList(&eventList);
197 if (CHIP_NO_ERROR == err)
199 isEventListPresent = true;
201 else if (CHIP_END_OF_TLV == err)
203 isEventListPresent = false;
208 if (isEventListPresent && nullptr != mpDelegate && !moreChunkedMessages)
210 chip::TLV::TLVReader eventListReader;
211 eventList.GetReader(&eventListReader);
212 err = mpDelegate->EventStreamReceived(mpExchangeCtx, &eventListReader);
217 if (!suppressResponse)
219 // TODO: Add status report support and correspond handler in ReadHandler, particular for situation when there
220 // are multiple reports
222 if (nullptr != mpDelegate && !moreChunkedMessages)
224 err = mpDelegate->ReportProcessed(this);
228 ChipLogFunctError(err);
232 void ReadClient::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext)
234 ChipLogProgress(DataManagement, "Time out! failed to receive report data from Exchange: %d",
235 apExchangeContext->GetExchangeId());
236 ClearExistingExchangeContext();
237 MoveToState(ClientState::Initialized);
238 if (nullptr != mpDelegate)
240 mpDelegate->ReportError(this, CHIP_ERROR_TIMEOUT);