Skip to content

Commit 1550630

Browse files
committed
[IM] Support put ReadClient to on hold when device is sleeping
1 parent 88b2d0c commit 1550630

File tree

3 files changed

+99
-1
lines changed

3 files changed

+99
-1
lines changed

src/app/ReadClient.cpp

+57
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ const char * ReadClient::GetStateStr() const
223223
return "AwaitingSubscribeResponse";
224224
case ClientState::SubscriptionActive:
225225
return "SubscriptionActive";
226+
case ClientState::IdleSubscription:
227+
return "IdleSubscription";
226228
}
227229
#endif // CHIP_DETAIL_LOGGING
228230
return "N/A";
@@ -427,6 +429,31 @@ CHIP_ERROR ReadClient::GenerateDataVersionFilterList(DataVersionFilterIBs::Build
427429
return CHIP_NO_ERROR;
428430
}
429431

432+
CHIP_ERROR ReadClient::WakeUp()
433+
{
434+
VerifyOrReturnError(IsIdle(), CHIP_ERROR_INCORRECT_STATE, "Not a valid subscription.");
435+
VerifyOrReturnError(mPeerActivePeriod != System::Clock::kZero, CHIP_ERROR_INCORRECT_STATE, "The device should not sleep.");
436+
MoveToState(ClientState::Idle);
437+
Close(CHIP_ERROR_TIMEOUT);
438+
return CHIP_NO_ERROR;
439+
}
440+
441+
void ReadClient::UpdateActivePeriod(System::Clock::Timeout aActivePeriod)
442+
{
443+
mPeerActivePeriod = aActivePeriod;
444+
}
445+
446+
CHIP_ERROR ReadClient::TouchPeerActiveTime(System::Clock::Timeout aActivePeriod)
447+
{
448+
System::Clock::Timestamp time;
449+
450+
ReturnLogErrorOnFailure(System::SystemClock().GetClock_RealTime(time));
451+
452+
mPeerActiveUntilTimestamp = time + aActivePeriod;
453+
454+
return CHIP_NO_ERROR;
455+
}
456+
430457
CHIP_ERROR ReadClient::OnMessageReceived(Messaging::ExchangeContext * apExchangeContext, const PayloadHeader & aPayloadHeader,
431458
System::PacketBufferHandle && aPayload)
432459
{
@@ -894,6 +921,24 @@ void ReadClient::OnLivenessTimeoutCallback(System::Layer * apSystemLayer, void *
894921
"Subscription Liveness timeout with SubscriptionID = 0x%08" PRIx32 ", Peer = %02x:" ChipLogFormatX64,
895922
_this->mSubscriptionId, _this->GetFabricIndex(), ChipLogValueX64(_this->GetPeerNodeId()));
896923

924+
if (mPeerActivePeriod != System::Clock::kZero)
925+
{
926+
// If device is sleeping, we mark the subscription as "IdleSubscription", and trigger resubscription on `WakeUp`.
927+
System::Clock::Timestamp time;
928+
CHIP_ERROR error = System::SystemClock().GetClock_RealTime(time);
929+
if (error != CHIP_NO_ERROR)
930+
{
931+
ChipLogError(DataManagement, "Failed to get current time: %s", ErrorStr(error));
932+
_this->Close(error, false);
933+
}
934+
if (time > mPeerActiveUntilTimestamp)
935+
{
936+
ChipLogProgress(DataManagement, "Peer is not active now, mark the subscription as IdleSubscription.");
937+
MoveToState(ClientState::IdleSubscription);
938+
return;
939+
}
940+
}
941+
897942
// We didn't get a message from the server on time; it's possible that it no
898943
// longer has a useful CASE session to us. Mark defunct all sessions that
899944
// have not seen peer activity in at least as long as our session.
@@ -998,6 +1043,18 @@ CHIP_ERROR ReadClient::SendSubscribeRequestImpl(const ReadPrepareParams & aReadP
9981043
mReadPrepareParams.mSessionHolder = aReadPrepareParams.mSessionHolder;
9991044
}
10001045

1046+
mPeerActivePeriod = aReadPrepareParams.mActivePeriod;
1047+
if (mPeerActivePeriod != System::Clock::kZero)
1048+
{
1049+
System::Clock::Timestamp time;
1050+
ReturnErrorOnFailure(System::SystemClock().GetClock_RealTime(time));
1051+
mPeerActiveUntilTimestamp = mPeerActivePeriod;
1052+
}
1053+
else
1054+
{
1055+
mPeerActiveUntilTimestamp = System::Clock::kZero;
1056+
}
1057+
10011058
mMinIntervalFloorSeconds = aReadPrepareParams.mMinIntervalFloorSeconds;
10021059

10031060
// Todo: Remove the below, Update span in ReadPrepareParams

src/app/ReadClient.h

+38-1
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,37 @@ class ReadClient : public Messaging::ExchangeDelegate
323323
*/
324324
CHIP_ERROR SendRequest(ReadPrepareParams & aReadPrepareParams);
325325

326+
/**
327+
* Wake up the sleeping subscription.
328+
*
329+
* When subscriptiing to ICD, the subscriber is expected to set the `mActivePeriod`
330+
* in `ReadPrepareParams`.
331+
*
332+
* @retval #others fail to send read request
333+
* @retval #CHIP_NO_ERROR Successfully waked up the subscription.
334+
* @retval #CHIP_ERROR_INCORRECT_STATE The transcation is not an active subscription
335+
*/
336+
CHIP_ERROR WakeUp();
337+
338+
/**
339+
* Update the active period of the device. This method **will not** update the
340+
* timestamp used to determine whether the device is idle.
341+
*
342+
* A Zero period means the device will always be active.
343+
*/
344+
void UpdateActivePeriod(System::Clock::Timeout aActivePeriod);
345+
346+
/**
347+
* Update the time used to determine whether the device is idle to the period from now.
348+
* This method **will not** update the active period for future wake-ups.
349+
*
350+
* A zero period means the device will sleep immediately.
351+
*
352+
* @retval #CHIP_NO_ERROR Successfully updated the active time.
353+
* @retval #others failed to update the active time.
354+
*/
355+
CHIP_ERROR TouchPeerActiveTime(System::Clock::Timeout aActivePeriod);
356+
326357
void OnUnsolicitedReportData(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload);
327358

328359
void OnUnsolicitedMessageFromPublisher()
@@ -477,6 +508,7 @@ class ReadClient : public Messaging::ExchangeDelegate
477508
AwaitingInitialReport, ///< The client is waiting for initial report
478509
AwaitingSubscribeResponse, ///< The client is waiting for subscribe response
479510
SubscriptionActive, ///< The client is maintaining subscription
511+
IdleSubscription, ///< The client is ICD and is sleeping
480512
};
481513

482514
enum class ReportType
@@ -500,7 +532,7 @@ class ReadClient : public Messaging::ExchangeDelegate
500532
* Check if current read client is being used
501533
*
502534
*/
503-
bool IsIdle() const { return mState == ClientState::Idle; }
535+
bool IsIdle() const { return mState == ClientState::Idle || mState == ClientState::IdleSubscription; }
504536
bool IsSubscriptionActive() const { return mState == ClientState::SubscriptionActive; }
505537
bool IsAwaitingInitialReport() const { return mState == ClientState::AwaitingInitialReport; }
506538
bool IsAwaitingSubscribeResponse() const { return mState == ClientState::AwaitingSubscribeResponse; }
@@ -612,6 +644,11 @@ class ReadClient : public Messaging::ExchangeDelegate
612644

613645
System::Clock::Timeout mLivenessTimeoutOverride = System::Clock::kZero;
614646

647+
// When the liveness timeout fired after `mPeerActiveUntilTimestamp`, the ReadClient will enter "Sleep" state until WakeUp() is called.
648+
// The Zero value means the device should always be active.
649+
System::Clock::Timeout mPeerActivePeriod = System::Clock::kZero;
650+
System::Clock::Timestamp mPeerActiveUntilTimestamp = System::Clock::kZero;
651+
615652
// End Of Container (0x18) uses one byte.
616653
static constexpr uint16_t kReservedSizeForEndOfContainer = 1;
617654
// Reserved size for the uint8_t InteractionModelRevision flag, which takes up 1 byte for the control tag and 1 byte for the

src/app/ReadPrepareParams.h

+4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ struct ReadPrepareParams
4747
uint16_t mMaxIntervalCeilingSeconds = 0;
4848
bool mKeepSubscriptions = false;
4949
bool mIsFabricFiltered = true;
50+
// The active period of the device, a Zero value means the device is always active.
51+
System::Clock::Timeout mActivePeriod = System::Clock::kZero;
5052

5153
ReadPrepareParams() {}
5254
ReadPrepareParams(const SessionHandle & sessionHandle) { mSessionHolder.Grab(sessionHandle); }
@@ -64,6 +66,7 @@ struct ReadPrepareParams
6466
mMaxIntervalCeilingSeconds = other.mMaxIntervalCeilingSeconds;
6567
mTimeout = other.mTimeout;
6668
mIsFabricFiltered = other.mIsFabricFiltered;
69+
mActivePeriod = other.mActivePeriod;
6770
other.mpEventPathParamsList = nullptr;
6871
other.mEventPathParamsListSize = 0;
6972
other.mpAttributePathParamsList = nullptr;
@@ -88,6 +91,7 @@ struct ReadPrepareParams
8891
mMaxIntervalCeilingSeconds = other.mMaxIntervalCeilingSeconds;
8992
mTimeout = other.mTimeout;
9093
mIsFabricFiltered = other.mIsFabricFiltered;
94+
mActivePeriod = other.mActivePeriod;
9195
other.mpEventPathParamsList = nullptr;
9296
other.mEventPathParamsListSize = 0;
9397
other.mpAttributePathParamsList = nullptr;

0 commit comments

Comments
 (0)