Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ICD] Add OnPeerTypeChange for dynamic ICD #31340

Merged
16 changes: 16 additions & 0 deletions src/app/InteractionModelEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,22 @@ void InteractionModelEngine::OnActiveModeNotification(ScopedNodeId aPeer)
}
}

void InteractionModelEngine::OnPeerTypeChange(ScopedNodeId aPeer, ReadClient::PeerType aType)
{
// TODO: Follow up to use a iterator function to avoid copy/paste here.
for (ReadClient * pListItem = mpActiveReadClientList; pListItem != nullptr;)
{
// It is possible that pListItem is destroyed by the app in OnPeerTypeChange.
// Get the next item before invoking `OnPeerTypeChange`.
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved
auto pNextItem = pListItem->GetNextClient();
if (ScopedNodeId(pListItem->GetPeerNodeId(), pListItem->GetFabricIndex()) == aPeer)
{
pListItem->OnPeerTypeChange(aType);
}
pListItem = pNextItem;
}
}

void InteractionModelEngine::AddReadClient(ReadClient * apReadClient)
{
apReadClient->SetNextClient(mpActiveReadClientList);
Expand Down
8 changes: 8 additions & 0 deletions src/app/InteractionModelEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,14 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler,
*/
void OnActiveModeNotification(ScopedNodeId aPeer);

/**
* Used to notify whether a peer becomes LIT ICD or vice versa.
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved
*
* The read client will call this function when it found any updates of the OperationMode attribute from ICD management
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved
* cluster. The application don't need to call this function usually.
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved
*/
void OnPeerTypeChange(ScopedNodeId aPeer, ReadClient::PeerType aType);
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved

/**
* Add a read client to the internally tracked list of weak references. This list is used to
* correctly dispatch unsolicited reports to the right matching handler by subscription ID.
Expand Down
61 changes: 61 additions & 0 deletions src/app/ReadClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
#include <messaging/ReliableMessageProtocolConfig.h>
#include <platform/LockTracker.h>

#include <app-common/zap-generated/cluster-objects.h>
#include <app-common/zap-generated/ids/Attributes.h>
#include <app-common/zap-generated/ids/Clusters.h>

namespace chip {
namespace app {

Expand Down Expand Up @@ -451,6 +455,19 @@ void ReadClient::OnActiveModeNotification()
TriggerResubscriptionForLivenessTimeout(CHIP_ERROR_TIMEOUT);
}

void ReadClient::OnPeerTypeChange(PeerType aType)
{
VerifyOrDie(mpImEngine->InActiveReadClientList(this));

mIsPeerLIT = (aType == PeerType::kLITICD);

// If the peer is no longer LIT, try to wake up the subscription and do resubsribe when necessary.
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved
if (!mIsPeerLIT)
{
OnActiveModeNotification();
}
}

CHIP_ERROR ReadClient::OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
System::PacketBufferHandle && aPayload)
{
Expand Down Expand Up @@ -663,6 +680,32 @@ void ReadClient::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContex
Close(CHIP_ERROR_TIMEOUT);
}

CHIP_ERROR ReadClient::ReadICDOperationModeFromAttributeDataIB(const TLV::TLVReader & aReader, PeerType & aType)
{
TLV::TLVReader reader;
reader.Init(aReader);

Clusters::IcdManagement::Attributes::OperatingMode::TypeInfo::DecodableType operatingMode;
erjiaqing marked this conversation as resolved.
Show resolved Hide resolved

CHIP_ERROR err = DataModel::Decode(reader, operatingMode);
ReturnErrorOnFailure(err);

switch (operatingMode)
{
case Clusters::IcdManagement::OperatingModeEnum::kSit:
aType = PeerType::kNormal;
break;
case Clusters::IcdManagement::OperatingModeEnum::kLit:
aType = PeerType::kLITICD;
break;
default:
err = CHIP_ERROR_INVALID_ARGUMENT;
break;
}

return err;
}

CHIP_ERROR ReadClient::ProcessAttributePath(AttributePathIB::Parser & aAttributePathParser,
ConcreteDataAttributePath & aAttributePath)
{
Expand Down Expand Up @@ -757,6 +800,24 @@ CHIP_ERROR ReadClient::ProcessAttributeReportIBs(TLV::TLVReader & aAttributeRepo
attributePath.mListOp = ConcreteDataAttributePath::ListOperation::ReplaceAll;
}

if (attributePath ==
ConcreteDataAttributePath(kRootEndpointId, Clusters::IcdManagement::Id,
Clusters::IcdManagement::Attributes::OperatingMode::Id))
erjiaqing marked this conversation as resolved.
Show resolved Hide resolved
{
PeerType peerType;
if (CHIP_NO_ERROR == ReadICDOperationModeFromAttributeDataIB(dataReader, peerType))
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved
{
// Since we are in the middle of parsing the attribute data, it is safe to call `OnPeerTypeChange`
// As it will only update the LIT / SIT bit for us without triggerring resubscription on this read client.
erjiaqing marked this conversation as resolved.
Show resolved Hide resolved
InteractionModelEngine::GetInstance()->OnPeerTypeChange(mPeer, peerType);
}
else
{
ChipLogError(DataManagement, "Failed to get ICD state from attribute data with error'%" CHIP_ERROR_FORMAT "'",
err.Format());
}
}

NoteReportingData();
mpCallback.OnAttributeData(attributePath, &dataReader, statusIB);
}
Expand Down
16 changes: 16 additions & 0 deletions src/app/ReadClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,12 @@ class ReadClient : public Messaging::ExchangeDelegate
Subscribe,
};

enum class PeerType : uint8_t
{
kNormal,
kLITICD,
};

/**
*
* Constructor.
Expand Down Expand Up @@ -524,6 +530,15 @@ class ReadClient : public Messaging::ExchangeDelegate
System::PacketBufferHandle && aPayload) override;
void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override;

/**
* Updates the type (LIT ICD or not) of the peer.
*
* When the subscription is active, this function will just set the flag. When the subscription is an InactiveICDSubscription,
* Setting the peer type to SIT or normal devices will also trigger resubscription.
yunhanw-google marked this conversation as resolved.
Show resolved Hide resolved
*
*/
void OnPeerTypeChange(PeerType aType);

/**
* Check if current read client is being used
*
Expand All @@ -544,6 +559,7 @@ class ReadClient : public Messaging::ExchangeDelegate
CHIP_ERROR BuildDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
const Span<AttributePathParams> & aAttributePaths,
const Span<DataVersionFilter> & aDataVersionFilters, bool & aEncodedDataVersionList);
CHIP_ERROR ReadICDOperationModeFromAttributeDataIB(const TLV::TLVReader & aReader, PeerType & aType);
CHIP_ERROR ProcessAttributeReportIBs(TLV::TLVReader & aAttributeDataIBsReader);
CHIP_ERROR ProcessEventReportIBs(TLV::TLVReader & aEventReportIBsReader);

Expand Down
Loading