Skip to content

Commit c770997

Browse files
[ICD]Retrigger subscription immediately when OnActiveModeNotification is invoked
1 parent ed1babf commit c770997

4 files changed

+67
-64
lines changed

src/app/InteractionModelEngine.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -1051,17 +1051,17 @@ void InteractionModelEngine::OnActiveModeNotification(ScopedNodeId aPeer)
10511051
}
10521052
}
10531053

1054-
void InteractionModelEngine::OnPeerTypeChange(ScopedNodeId aPeer, ReadClient::PeerType aType)
1054+
void InteractionModelEngine::OnPeerOperatingModeChange(ScopedNodeId aPeer, ReadClient::PeerOperatingMode aMode)
10551055
{
10561056
// TODO: Follow up to use a iterator function to avoid copy/paste here.
10571057
for (ReadClient * pListItem = mpActiveReadClientList; pListItem != nullptr;)
10581058
{
1059-
// It is possible that pListItem is destroyed by the app in OnPeerTypeChange.
1060-
// Get the next item before invoking `OnPeerTypeChange`.
1059+
// It is possible that pListItem is destroyed by the app in OnPeerOperatingModeChange.
1060+
// Get the next item before invoking `OnPeerOperatingModeChange`.
10611061
auto pNextItem = pListItem->GetNextClient();
10621062
if (ScopedNodeId(pListItem->GetPeerNodeId(), pListItem->GetFabricIndex()) == aPeer)
10631063
{
1064-
pListItem->OnPeerTypeChange(aType);
1064+
pListItem->OnPeerOperatingModeChange(aMode);
10651065
}
10661066
pListItem = pNextItem;
10671067
}

src/app/InteractionModelEngine.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,12 @@ class InteractionModelEngine : public Messaging::UnsolicitedMessageHandler,
245245
void OnActiveModeNotification(ScopedNodeId aPeer);
246246

247247
/**
248-
* Used to notify when a peer becomes LIT ICD or vice versa.
248+
* Used to notify when a peer operating mode becomes LIT ICD or vice versa.
249249
*
250250
* ReadClient will call this function when it finds any updates of the OperatingMode attribute from ICD management
251251
* cluster. The application doesn't need to call this function, usually.
252252
*/
253-
void OnPeerTypeChange(ScopedNodeId aPeer, ReadClient::PeerType aType);
253+
void OnPeerOperatingModeChange(ScopedNodeId aPeer, ReadClient::PeerOperatingMode aMode);
254254

255255
/**
256256
* Add a read client to the internally tracked list of weak references. This list is used to

src/app/ReadClient.cpp

+46-43
Original file line numberDiff line numberDiff line change
@@ -208,13 +208,11 @@ void ReadClient::Close(CHIP_ERROR aError, bool allowResubscription)
208208
aError = mpCallback.OnResubscriptionNeeded(this, aError);
209209
if (aError == CHIP_NO_ERROR)
210210
{
211-
return;
212-
}
213-
if (aError == CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT)
214-
{
215-
VerifyOrDie(originalReason == CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT);
216-
ChipLogProgress(DataManagement, "ICD device is inactive mark subscription as InactiveICDSubscription");
217-
MoveToState(ClientState::InactiveICDSubscription);
211+
if (originalReason == CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT)
212+
{
213+
ChipLogProgress(DataManagement, "ICD device is unreachable, mark subscription as InactiveICDSubscription, retrying is scheduled");
214+
MoveToState(ClientState::InactiveICDSubscription);
215+
}
218216
return;
219217
}
220218
}
@@ -484,26 +482,25 @@ CHIP_ERROR ReadClient::GenerateDataVersionFilterList(DataVersionFilterIBs::Build
484482

485483
void ReadClient::OnActiveModeNotification()
486484
{
487-
// This function just tries to complete the deferred resubscription logic in `OnLivenessTimeoutCallback`.
488485
VerifyOrDie(mpImEngine->InActiveReadClientList(this));
489-
// If we are not in InactiveICDSubscription state, that means the liveness timeout has not been reached. Simply do nothing.
486+
// If we are in InactiveICDSubscription state, it means the LIT ICD device was unreachable, and ClearActiveSubscriptionState
487+
// should have been cleared in previous close call, now it transitions to the reachable status, client needs to cancel
488+
// scheduled resubscription and trigger a new one immediately. Case session should have been defunct when going
489+
// into InactiveICDSubscription state during previous close call,
490490
VerifyOrReturn(IsInactiveICDSubscription());
491-
492-
// When we reach here, the subscription definitely exceeded the liveness timeout. Just continue the unfinished resubscription
493-
// logic in `OnLivenessTimeoutCallback`.
494-
TriggerResubscriptionForLivenessTimeout(CHIP_ERROR_TIMEOUT);
491+
CloseSession();
492+
CancelResubscribeTimer();
493+
MoveToState(ClientState::Idle);
494+
OnResubscribeTimerCallback(nullptr, this);
495495
}
496496

497-
void ReadClient::OnPeerTypeChange(PeerType aType)
497+
void ReadClient::OnPeerOperatingModeChange(PeerOperatingMode aMode)
498498
{
499499
VerifyOrDie(mpImEngine->InActiveReadClientList(this));
500+
ChipLogProgress(DataManagement, "Peer operation mode is now %s LIT ICD.", mPeerOperatingMode == PeerOperatingMode::kLITICD ? "a" : "not a");
500501

501-
mIsPeerLIT = (aType == PeerType::kLITICD);
502-
503-
ChipLogProgress(DataManagement, "Peer is now %s LIT ICD.", mIsPeerLIT ? "a" : "not a");
504-
505-
// If the peer is no longer LIT, try to wake up the subscription and do resubscribe when necessary.
506-
if (!mIsPeerLIT)
502+
// If the peer operating mode is no longer LIT, try to wake up the subscription and do resubscribe when necessary.
503+
if (mPeerOperatingMode == PeerOperatingMode::kNormal)
507504
{
508505
OnActiveModeNotification();
509506
}
@@ -720,10 +717,18 @@ void ReadClient::OnResponseTimeout(Messaging::ExchangeContext * apExchangeContex
720717
ChipLogError(DataManagement, "Time out! failed to receive report data from Exchange: " ChipLogFormatExchange,
721718
ChipLogValueExchange(apExchangeContext));
722719

723-
Close(CHIP_ERROR_TIMEOUT);
720+
if (IsPeerLIT())
721+
{
722+
Close(CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT);
723+
}
724+
else
725+
{
726+
Close(CHIP_ERROR_TIMEOUT);
727+
}
728+
724729
}
725730

726-
CHIP_ERROR ReadClient::ReadICDOperatingModeFromAttributeDataIB(TLV::TLVReader && aReader, PeerType & aType)
731+
CHIP_ERROR ReadClient::ReadICDOperatingModeFromAttributeDataIB(TLV::TLVReader && aReader, PeerOperatingMode & aMode)
727732
{
728733
Clusters::IcdManagement::Attributes::OperatingMode::TypeInfo::DecodableType operatingMode;
729734

@@ -733,10 +738,12 @@ CHIP_ERROR ReadClient::ReadICDOperatingModeFromAttributeDataIB(TLV::TLVReader &&
733738
switch (operatingMode)
734739
{
735740
case Clusters::IcdManagement::OperatingModeEnum::kSit:
736-
aType = PeerType::kNormal;
741+
aMode = PeerOperatingMode::kNormal;
737742
break;
738743
case Clusters::IcdManagement::OperatingModeEnum::kLit:
739-
aType = PeerType::kLITICD;
744+
aMode = PeerOperatingMode::kLITICD;
745+
// If operating mode is LIT, this device should be LIT ICD.
746+
mIsPeerLIT = true;
740747
break;
741748
default:
742749
err = CHIP_ERROR_INVALID_ARGUMENT;
@@ -843,14 +850,14 @@ CHIP_ERROR ReadClient::ProcessAttributeReportIBs(TLV::TLVReader & aAttributeRepo
843850
if (attributePath.MatchesConcreteAttributePath(ConcreteAttributePath(
844851
kRootEndpointId, Clusters::IcdManagement::Id, Clusters::IcdManagement::Attributes::OperatingMode::Id)))
845852
{
846-
PeerType peerType;
853+
PeerOperatingMode peerMode;
847854
TLV::TLVReader operatingModeTlvReader;
848855
operatingModeTlvReader.Init(dataReader);
849-
if (CHIP_NO_ERROR == ReadICDOperatingModeFromAttributeDataIB(std::move(operatingModeTlvReader), peerType))
856+
if (CHIP_NO_ERROR == ReadICDOperatingModeFromAttributeDataIB(std::move(operatingModeTlvReader), peerMode))
850857
{
851-
// It is safe to call `OnPeerTypeChange` since we are in the middle of parsing the attribute data, And
858+
// It is safe to call `OnPeerOperatingModeChange` since we are in the middle of parsing the attribute data, And
852859
// the subscription should be active so `OnActiveModeNotification` is a no-op in this case.
853-
InteractionModelEngine::GetInstance()->OnPeerTypeChange(mPeer, peerType);
860+
InteractionModelEngine::GetInstance()->OnPeerOperatingModeChange(mPeer, peerMode);
854861
}
855862
else
856863
{
@@ -1029,15 +1036,16 @@ void ReadClient::OnLivenessTimeoutCallback(System::Layer * apSystemLayer, void *
10291036
"Subscription Liveness timeout with SubscriptionID = 0x%08" PRIx32 ", Peer = %02x:" ChipLogFormatX64,
10301037
_this->mSubscriptionId, _this->GetFabricIndex(), ChipLogValueX64(_this->GetPeerNodeId()));
10311038

1032-
if (_this->mIsPeerLIT)
1039+
if (_this->IsPeerLIT())
10331040
{
10341041
subscriptionTerminationCause = CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT;
10351042
}
10361043

1037-
_this->TriggerResubscriptionForLivenessTimeout(subscriptionTerminationCause);
1044+
_this->CloseSession();
1045+
_this->Close(subscriptionTerminationCause);
10381046
}
10391047

1040-
void ReadClient::TriggerResubscriptionForLivenessTimeout(CHIP_ERROR aReason)
1048+
void ReadClient::CloseSession()
10411049
{
10421050
// We didn't get a message from the server on time; it's possible that it no
10431051
// longer has a useful CASE session to us. Mark defunct all sessions that
@@ -1060,8 +1068,6 @@ void ReadClient::TriggerResubscriptionForLivenessTimeout(CHIP_ERROR aReason)
10601068
session->MarkAsDefunct();
10611069
});
10621070
}
1063-
1064-
Close(aReason);
10651071
}
10661072

10671073
CHIP_ERROR ReadClient::ProcessSubscribeResponse(System::PacketBufferHandle && aPayload)
@@ -1265,12 +1271,6 @@ CHIP_ERROR ReadClient::SendSubscribeRequestImpl(const ReadPrepareParams & aReadP
12651271

12661272
CHIP_ERROR ReadClient::DefaultResubscribePolicy(CHIP_ERROR aTerminationCause)
12671273
{
1268-
if (aTerminationCause == CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT)
1269-
{
1270-
ChipLogProgress(DataManagement, "ICD device is inactive, skipping scheduling resubscribe within DefaultResubscribePolicy");
1271-
return CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT;
1272-
}
1273-
12741274
VerifyOrReturnError(IsIdle(), CHIP_ERROR_INCORRECT_STATE);
12751275

12761276
auto timeTillNextResubscription = ComputeTimeTillNextSubscription();
@@ -1305,9 +1305,9 @@ void ReadClient::HandleDeviceConnectionFailure(void * context, const Operational
13051305
{
13061306
ReadClient * const _this = static_cast<ReadClient *>(context);
13071307
VerifyOrDie(_this != nullptr);
1308-
1308+
CHIP_ERROR err = failureInfo.error;
13091309
ChipLogError(DataManagement, "Failed to establish CASE for re-subscription with error '%" CHIP_ERROR_FORMAT "'",
1310-
failureInfo.error.Format());
1310+
err.Format());
13111311

13121312
#if CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
13131313
#if CHIP_DETAIL_LOGGING
@@ -1322,7 +1322,11 @@ void ReadClient::HandleDeviceConnectionFailure(void * context, const Operational
13221322
_this->mMinimalResubscribeDelay = System::Clock::kZero;
13231323
#endif // CHIP_CONFIG_ENABLE_BUSY_HANDLING_FOR_OPERATIONAL_SESSION_SETUP
13241324

1325-
_this->Close(failureInfo.error);
1325+
if (_this->IsPeerLIT() && err == CHIP_ERROR_TIMEOUT)
1326+
{
1327+
err = CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT;
1328+
}
1329+
_this->Close(err);
13261330
}
13271331

13281332
void ReadClient::OnResubscribeTimerCallback(System::Layer * /* If this starts being used, fix callers that pass nullptr */,
@@ -1334,7 +1338,6 @@ void ReadClient::OnResubscribeTimerCallback(System::Layer * /* If this starts be
13341338
_this->mIsResubscriptionScheduled = false;
13351339

13361340
CHIP_ERROR err;
1337-
13381341
ChipLogProgress(DataManagement, "OnResubscribeTimerCallback: ForceCASE = %d", _this->mForceCaseOnNextResub);
13391342
_this->mNumRetries++;
13401343

src/app/ReadClient.h

+15-15
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,6 @@ class ReadClient : public Messaging::ExchangeDelegate
165165
* ReadClient::DefaultResubscribePolicy is broken down into its constituent methods that are publicly available for
166166
* applications to call and sequence.
167167
*
168-
* If the peer is LIT ICD, and the timeout is reached, `aTerminationCause` will be
169-
* `CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT`. In this case, returning `CHIP_NO_ERROR` will still trigger a resubscribe
170-
* attempt, while returning `CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT` will put the subscription in the
171-
* `InactiveICDSubscription` state. In the latter case, OnResubscriptionNeeded will be called again when
172-
* `OnActiveModeNotification` is called.
173-
*
174168
* If the method is over-ridden, it's the application's responsibility to take the appropriate steps needed to eventually
175169
* call-back into the ReadClient object to schedule a re-subscription (by invoking ReadClient::ScheduleResubscription).
176170
*
@@ -292,7 +286,7 @@ class ReadClient : public Messaging::ExchangeDelegate
292286
Subscribe,
293287
};
294288

295-
enum class PeerType : uint8_t
289+
enum class PeerOperatingMode : uint8_t
296290
{
297291
kNormal,
298292
kLITICD,
@@ -350,12 +344,12 @@ class ReadClient : public Messaging::ExchangeDelegate
350344
/**
351345
* Re-activate an inactive subscription.
352346
*
353-
* When subscribing to LIT-ICD and liveness timeout reached and OnResubscriptionNeeded returns
354-
* CHIP_ERROR_LIT_SUBSCRIBE_INACTIVE_TIMEOUT, the read client will move to the InactiveICDSubscription state and
355-
* resubscription can be triggered via OnActiveModeNotification().
347+
* When subscribing to LIT-ICD and timeout reached, the read client will move to the InactiveICDSubscription state
348+
* and resubscription should have been scheduled by previous close call, resubscription can be triggered immediately via
349+
* OnActiveModeNotification() when receiving check-in message.
356350
*
357351
* If the subscription is not in the `InactiveICDSubscription` state, this function will do nothing. So it is always safe to
358-
* call this function when a check-in message is received.
352+
* call this function when a check-in message is received.
359353
*/
360354
void OnActiveModeNotification();
361355

@@ -503,6 +497,10 @@ class ReadClient : public Messaging::ExchangeDelegate
503497
*/
504498
Optional<System::Clock::Timeout> GetSubscriptionTimeout();
505499

500+
501+
bool IsPeerLIT() { return mIsPeerLIT; }
502+
PeerOperatingMode GetLITOperatingMode() { return mPeerOperatingMode; }
503+
506504
private:
507505
friend class TestReadInteraction;
508506
friend class InteractionModelEngine;
@@ -534,13 +532,13 @@ class ReadClient : public Messaging::ExchangeDelegate
534532
void OnResponseTimeout(Messaging::ExchangeContext * apExchangeContext) override;
535533

536534
/**
537-
* Updates the type (LIT ICD or not) of the peer.
535+
* Updates the operating mode (LIT ICD or not) of the peer.
538536
*
539537
* When the subscription is active, this function will just set the flag. When the subscription is an InactiveICDSubscription,
540538
* setting the peer type to SIT or normal devices will also trigger a resubscription attempt.
541539
*
542540
*/
543-
void OnPeerTypeChange(PeerType aType);
541+
void OnPeerOperatingModeChange(PeerOperatingMode aMode);
544542

545543
/**
546544
* Check if current read client is being used
@@ -562,7 +560,7 @@ class ReadClient : public Messaging::ExchangeDelegate
562560
CHIP_ERROR BuildDataVersionFilterList(DataVersionFilterIBs::Builder & aDataVersionFilterIBsBuilder,
563561
const Span<AttributePathParams> & aAttributePaths,
564562
const Span<DataVersionFilter> & aDataVersionFilters, bool & aEncodedDataVersionList);
565-
CHIP_ERROR ReadICDOperatingModeFromAttributeDataIB(TLV::TLVReader && aReader, PeerType & aType);
563+
CHIP_ERROR ReadICDOperatingModeFromAttributeDataIB(TLV::TLVReader && aReader, PeerOperatingMode & aMode);
566564
CHIP_ERROR ProcessAttributeReportIBs(TLV::TLVReader & aAttributeDataIBsReader);
567565
CHIP_ERROR ProcessEventReportIBs(TLV::TLVReader & aEventReportIBsReader);
568566

@@ -572,7 +570,7 @@ class ReadClient : public Messaging::ExchangeDelegate
572570
CHIP_ERROR ComputeLivenessCheckTimerTimeout(System::Clock::Timeout * aTimeout);
573571
void CancelLivenessCheckTimer();
574572
void CancelResubscribeTimer();
575-
void TriggerResubscriptionForLivenessTimeout(CHIP_ERROR aReason);
573+
void CloseSession();
576574
void MoveToState(const ClientState aTargetState);
577575
CHIP_ERROR ProcessAttributePath(AttributePathIB::Parser & aAttributePath, ConcreteDataAttributePath & aClusterInfo);
578576
CHIP_ERROR ProcessReportData(System::PacketBufferHandle && aPayload, ReportType aReportType);
@@ -667,6 +665,8 @@ class ReadClient : public Messaging::ExchangeDelegate
667665

668666
bool mIsPeerLIT = false;
669667

668+
PeerOperatingMode mPeerOperatingMode = PeerOperatingMode::kNormal ;
669+
670670
// End Of Container (0x18) uses one byte.
671671
static constexpr uint16_t kReservedSizeForEndOfContainer = 1;
672672
// Reserved size for the uint8_t InteractionModelRevision flag, which takes up 1 byte for the control tag and 1 byte for the

0 commit comments

Comments
 (0)