Skip to content

Commit

Permalink
Add IM/Ember Read/Writer Interface and attribute read for IM
Browse files Browse the repository at this point in the history
Summary of Changes:
-- Add initial IM read attribute implementation and ember read/write
interface so that read client can send IM read request with attribute
path,  interaction model engine receive this request and ask
reporting engine generate the corresponding interested attributes and
send it back via read hander.

-- Add unit and cirque integration test
  • Loading branch information
yunhanw-google committed Apr 22, 2021
1 parent 0e9ec10 commit 9fbb803
Show file tree
Hide file tree
Showing 15 changed files with 486 additions and 50 deletions.
10 changes: 1 addition & 9 deletions src/app/AttributePathParams.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,7 @@ struct AttributePathParams
mNodeId(aNodeId),
mEndpointId(aEndpointId), mClusterId(aClusterId), mFieldId(aFieldId), mListIndex(aListIndex), mFlags(aFlags)
{}
AttributePathParams(const AttributePathParams & aAttributePathParams)
{
mNodeId = aAttributePathParams.mNodeId;
mEndpointId = aAttributePathParams.mEndpointId;
mClusterId = aAttributePathParams.mClusterId;
mFieldId = aAttributePathParams.mFieldId;
mListIndex = aAttributePathParams.mListIndex;
mFlags = aAttributePathParams.mFlags;
}
AttributePathParams(){};
bool IsSamePath(const AttributePathParams & other) const
{
if (other.mNodeId != mNodeId || other.mEndpointId != mEndpointId || other.mClusterId != mClusterId)
Expand Down
1 change: 1 addition & 0 deletions src/app/ClusterInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct ClusterInfo
ClusterInfo(const AttributePathParams & aAttributePathParams, bool aDirty) :
mAttributePathParams(aAttributePathParams), mDirty(aDirty)
{}
ClusterInfo() {}
bool IsDirty() { return mDirty; }
void SetDirty() { mDirty = true; }
void ClearDirty() { mDirty = false; }
Expand Down
35 changes: 35 additions & 0 deletions src/app/InteractionModelEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,44 @@ 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(NodeId aNodeId, ClusterId aClusterId, EndpointId aEndPointId, FieldId aFieldId, TLV::TLVWriter & aWriter)
{
ChipLogDetail(DataManagement,
"Received Cluster Command: Cluster=%" PRIx16 " NodeId=%" PRIx64 " Endpoint=%" PRIx8 " FieldId=%" PRIx8,
aClusterId, aNodeId, aEndPointId, aFieldId);
ChipLogError(DataManagement,
"Default ReadSingleClusterData is called, this should be replaced by actual dispatched for cluster");
return CHIP_NO_ERROR;
}

CHIP_ERROR __attribute__((weak))
WriteSingleClusterData(NodeId aNodeId, ClusterId aClusterId, EndpointId aEndPointId, FieldId aFieldId, TLV::TLVReader & aReader)
{
ChipLogDetail(DataManagement,
"Received Cluster Command: Cluster=%" PRIx16 " NodeId=%" PRIx64 " Endpoint=%" PRIx8 " FieldId=%" PRIx8,
aClusterId, aNodeId, aEndPointId, aFieldId);
ChipLogError(DataManagement,
"Default WriteSingleClusterData is called, this should be replaced by actual dispatched for cluster");
return CHIP_NO_ERROR;
}

uint16_t InteractionModelEngine::GetReadClientArrayIndex(const ReadClient * const apReadClient) const
{
return static_cast<uint16_t>(apReadClient - mReadClients);
}

CHIP_ERROR InteractionModelEngine::GetFirstAvailableClusterInfo(ClusterInfo *& apClusterInfo)
{
if (mNumClusterInfos >= IM_SERVER_MAX_NUM_PATH_GROUPS)
{
return CHIP_ERROR_NO_MEMORY;
}
apClusterInfo = &mClusterInfoPool[mNumClusterInfos];
mNumClusterInfos++;
apClusterInfo->ClearDirty();
return CHIP_NO_ERROR;
}

} // namespace app
} // namespace chip
19 changes: 17 additions & 2 deletions src/app/InteractionModelEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,29 @@
#include <support/logging/CHIPLogging.h>
#include <system/SystemPacketBuffer.h>

#include <app/ClusterInfo.h>
#include <app/Command.h>
#include <app/CommandHandler.h>
#include <app/CommandSender.h>
#include <app/InteractionModelDelegate.h>
#include <app/ReadClient.h>
#include <app/ReadHandler.h>
#include <app/reporting/Engine.h>
#include <app/util/basic-types.h>

#define CHIP_MAX_NUM_COMMAND_HANDLER 1
#define CHIP_MAX_NUM_COMMAND_SENDER 1
#define CHIP_MAX_NUM_READ_CLIENT 1
#define CHIP_MAX_NUM_READ_HANDLER 1
#define CHIP_MAX_REPORTS_IN_FLIGHT 1
#define IM_SERVER_MAX_NUM_PATH_GROUPS 256

namespace chip {
namespace app {

constexpr size_t kMaxSecureSduLengthBytes = 1024;
constexpr uint32_t kImMessageTimeoutMsec = 3000;

constexpr FieldId kRootFieldId = 0;
/**
* @class InteractionModelEngine
*
Expand Down Expand Up @@ -127,6 +130,13 @@ class InteractionModelEngine : public Messaging::ExchangeDelegate

reporting::Engine & GetReportingEngine() { return mReportingEngine; }

CHIP_ERROR GetFirstAvailableClusterInfo(ClusterInfo *& apClusterInfo);

long GetNumClusterInfos() { return mNumClusterInfos; };
ClusterInfo * GetClusterInfoPool() { return mClusterInfoPool; };
void ShrinkCluster(long aNumberCluster) { mNumClusterInfos -= aNumberCluster; };
ReadHandler * GetReadHandler(size_t aIndex) { return &mReadHandlers[aIndex]; };

private:
friend class reporting::Engine;
void OnUnknownMsgType(Messaging::ExchangeContext * apExchangeContext, const PacketHeader & aPacketHeader,
Expand All @@ -151,10 +161,15 @@ class InteractionModelEngine : public Messaging::ExchangeDelegate
ReadClient mReadClients[CHIP_MAX_NUM_READ_CLIENT];
ReadHandler mReadHandlers[CHIP_MAX_NUM_READ_HANDLER];
reporting::Engine mReportingEngine;
long mNumClusterInfos = 0;
ClusterInfo mClusterInfoPool[IM_SERVER_MAX_NUM_PATH_GROUPS];
};

void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aCommandId, chip::EndpointId aEndPointId,
chip::TLV::TLVReader & aReader, Command * apCommandObj);

CHIP_ERROR ReadSingleClusterData(NodeId aNodeId, ClusterId aClusterId, EndpointId aEndPointId, FieldId aFieldId,
TLV::TLVWriter & aWriter);
CHIP_ERROR WriteSingleClusterData(NodeId aNodeId, ClusterId aClusterId, EndpointId aEndPointId, FieldId aFieldId,
TLV::TLVReader & aReader);
} // namespace app
} // namespace chip
133 changes: 107 additions & 26 deletions src/app/ReadClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ void ReadClient::MoveToState(const ClientState aTargetState)
}

CHIP_ERROR ReadClient::SendReadRequest(NodeId aNodeId, Transport::AdminId aAdminId, EventPathParams * apEventPathParamsList,
size_t aEventPathParamsListSize)
size_t aEventPathParamsListSize, AttributePathParams * apAttributePathParamsList,
size_t aAttributePathParamsListSize)
{
CHIP_ERROR err = CHIP_NO_ERROR;
System::PacketBufferHandle msgBuf;
Expand All @@ -104,6 +105,33 @@ CHIP_ERROR ReadClient::SendReadRequest(NodeId aNodeId, Transport::AdminId aAdmin
{
// TODO: fill to construct event paths
}

if (aAttributePathParamsListSize != 0 && apAttributePathParamsList != nullptr)
{
AttributePathList::Builder attributePathListBuilder = request.CreateAttributePathListBuilder();
SuccessOrExit(attributePathListBuilder.GetError());
for (size_t index = 0; index < aAttributePathParamsListSize; index++)
{
AttributePath::Builder attributePathBuilder = attributePathListBuilder.CreateAttributePathBuilder();
attributePathBuilder.NodeId(apAttributePathParamsList[index].mNodeId)
.EndpointId(apAttributePathParamsList[index].mEndpointId)
.ClusterId(apAttributePathParamsList[index].mClusterId);
if (apAttributePathParamsList[index].mFlags == AttributePathFlags::kFieldIdValid)
{
attributePathBuilder.FieldId(apAttributePathParamsList[index].mFieldId);
}
else if (apAttributePathParamsList[index].mFlags == AttributePathFlags::kListIndexValid)
{
attributePathBuilder.ListIndex(apAttributePathParamsList[index].mListIndex);
}
else
{
err = CHIP_ERROR_INVALID_ARGUMENT;
ExitNow();
}
SuccessOrExit(attributePathBuilder.GetError());
}
}
request.EndOfReadRequest();
SuccessOrExit(request.GetError());

Expand Down Expand Up @@ -139,7 +167,6 @@ void ReadClient::OnMessageReceived(Messaging::ExchangeContext * apExchangeContex

ClearExistingExchangeContext();
MoveToState(ClientState::Initialized);

if (mpDelegate != nullptr)
{
if (err != CHIP_NO_ERROR)
Expand Down Expand Up @@ -171,10 +198,12 @@ CHIP_ERROR ReadClient::ProcessReportData(System::PacketBufferHandle aPayload)
CHIP_ERROR err = CHIP_NO_ERROR;
ReportData::Parser report;

bool isEventListPresent = false;
bool suppressResponse = false;
bool moreChunkedMessages = false;

bool isEventListPresent = false;
bool isAttributeDataListPresent = false;
bool suppressResponse = false;
bool moreChunkedMessages = false;
EventList::Parser eventList;
AttributeDataList::Parser attributeDataList;
System::PacketBufferTLVReader reader;

reader.Init(std::move(aPayload));
Expand Down Expand Up @@ -202,30 +231,35 @@ CHIP_ERROR ReadClient::ProcessReportData(System::PacketBufferHandle aPayload)
}
SuccessOrExit(err);

err = report.GetEventDataList(&eventList);
isEventListPresent = (err == CHIP_NO_ERROR);
if (err == CHIP_END_OF_TLV)
{
EventList::Parser eventList;
err = CHIP_NO_ERROR;
}
SuccessOrExit(err);

err = report.GetEventDataList(&eventList);
if (CHIP_NO_ERROR == err)
{
isEventListPresent = true;
}
else if (CHIP_END_OF_TLV == err)
{
isEventListPresent = false;
err = CHIP_NO_ERROR;
}
if (isEventListPresent && nullptr != mpDelegate)
{
chip::TLV::TLVReader eventListReader;
eventList.GetReader(&eventListReader);
err = mpDelegate->EventStreamReceived(mpExchangeCtx, &eventListReader);
SuccessOrExit(err);
}

VerifyOrExit(moreChunkedMessages == false, err = CHIP_ERROR_MESSAGE_INCOMPLETE);

if (isEventListPresent && nullptr != mpDelegate)
{
chip::TLV::TLVReader eventListReader;
eventList.GetReader(&eventListReader);
err = mpDelegate->EventStreamReceived(mpExchangeCtx, &eventListReader);
SuccessOrExit(err);
}
err = report.GetAttributeDataList(&attributeDataList);
isAttributeDataListPresent = (err == CHIP_NO_ERROR);
if (err == CHIP_END_OF_TLV)
{
err = CHIP_NO_ERROR;
}
SuccessOrExit(err);
if (isAttributeDataListPresent && nullptr != mpDelegate && !moreChunkedMessages)
{
chip::TLV::TLVReader attributeDataListReader;
attributeDataList.GetReader(&attributeDataListReader);
err = ProcessAttributeDataList(attributeDataListReader);
SuccessOrExit(err);
}

if (!suppressResponse)
Expand All @@ -250,5 +284,52 @@ void ReadClient::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContex
mpDelegate->ReportError(this, CHIP_ERROR_TIMEOUT);
}
}

CHIP_ERROR ReadClient::ProcessAttributeDataList(TLV::TLVReader & aAttributeDataListReader)
{
CHIP_ERROR err = CHIP_NO_ERROR;
while (CHIP_NO_ERROR == (err = aAttributeDataListReader.Next()))
{
NodeId nodeId = 0;
EndpointId endpointId = 0;
ClusterId clusterId = 0;
FieldId fieldId = 0;
chip::TLV::TLVReader dataReader;
AttributeDataElement::Parser element;
AttributePath::Parser attributePathParser;
TLV::TLVReader reader = aAttributeDataListReader;
err = element.Init(reader);
SuccessOrExit(err);

err = element.GetAttributePath(&attributePathParser);
SuccessOrExit(err);

err = attributePathParser.GetNodeId(&nodeId);
SuccessOrExit(err);

err = attributePathParser.GetEndpointId(&endpointId);
SuccessOrExit(err);

err = attributePathParser.GetClusterId(&clusterId);
SuccessOrExit(err);

err = attributePathParser.GetFieldId(&fieldId);
SuccessOrExit(err);

err = element.GetData(&dataReader);
SuccessOrExit(err);
err = WriteSingleClusterData(nodeId, clusterId, endpointId, fieldId, dataReader);
SuccessOrExit(err);
}

if (CHIP_END_OF_TLV == err)
{
err = CHIP_NO_ERROR;
}

exit:
ChipLogFunctError(err);
return err;
}
}; // namespace app
}; // namespace chip
7 changes: 6 additions & 1 deletion src/app/ReadClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,14 @@ class ReadClient : public Messaging::ExchangeDelegate
* @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);
size_t aEventPathParamsListSize, AttributePathParams * apAttributePathParamsList,
size_t aAttributePathParamsListSize);

private:
friend class TestReadInteraction;
Expand Down Expand Up @@ -114,6 +117,8 @@ class ReadClient : public Messaging::ExchangeDelegate
*/
bool IsFree() const { return mState == ClientState::Uninitialized; };

CHIP_ERROR ProcessAttributeDataList(TLV::TLVReader & aAttributeDataListReader);

void MoveToState(const ClientState aTargetState);
CHIP_ERROR ProcessReportData(System::PacketBufferHandle aPayload);
CHIP_ERROR ClearExistingExchangeContext();
Expand Down
Loading

0 comments on commit 9fbb803

Please sign in to comment.