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] Report before idle mode #28714

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/app/icd/ICDManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ void ICDManager::Shutdown()
// cancel any running timer of the icd
DeviceLayer::SystemLayer().CancelTimer(OnIdleModeDone, this);
DeviceLayer::SystemLayer().CancelTimer(OnActiveModeDone, this);
DeviceLayer::SystemLayer().CancelTimer(OnTransitionToIdle, this);
mICDMode = ICDMode::SIT;
mOperationalState = OperationalState::IdleMode;
mStorage = nullptr;
Expand Down Expand Up @@ -157,6 +158,9 @@ void ICDManager::UpdateOperationState(OperationalState state)
mOperationalState = OperationalState::ActiveMode;
uint32_t activeModeInterval = IcdManagementServer::GetInstance().GetActiveModeInterval();
DeviceLayer::SystemLayer().StartTimer(System::Clock::Timeout(activeModeInterval), OnActiveModeDone, this);
uint32_t activeModeJitterInterval =
(activeModeInterval >= ICD_ACTIVE_TIME_JITTER_MS) ? activeModeInterval - ICD_ACTIVE_TIME_JITTER_MS : 0;
DeviceLayer::SystemLayer().StartTimer(System::Clock::Timeout(activeModeJitterInterval), OnTransitionToIdle, this);

CHIP_ERROR err = DeviceLayer::ConnectivityMgr().SetPollingInterval(GetFastPollingInterval());
if (err != CHIP_NO_ERROR)
Expand All @@ -170,6 +174,13 @@ void ICDManager::UpdateOperationState(OperationalState state)
{
uint16_t activeModeThreshold = IcdManagementServer::GetInstance().GetActiveModeThreshold();
DeviceLayer::SystemLayer().ExtendTimerTo(System::Clock::Timeout(activeModeThreshold), OnActiveModeDone, this);
uint16_t activeModeJitterThreshold =
(activeModeThreshold >= ICD_ACTIVE_TIME_JITTER_MS) ? activeModeThreshold - ICD_ACTIVE_TIME_JITTER_MS : 0;
if (!mTransitionToIdleCalled)
{
DeviceLayer::SystemLayer().ExtendTimerTo(System::Clock::Timeout(activeModeJitterThreshold), OnTransitionToIdle,
this);
}
}
}
}
Expand All @@ -195,6 +206,10 @@ void ICDManager::OnIdleModeDone(System::Layer * aLayer, void * appState)
{
ICDManager * pIcdManager = reinterpret_cast<ICDManager *>(appState);
pIcdManager->UpdateOperationState(OperationalState::ActiveMode);

// We only reset this flag when idle mode is complete to avoid re-triggering the check when an event brings us back to active,
// which could cause a loop.
pIcdManager->mTransitionToIdleCalled = false;
}

void ICDManager::OnActiveModeDone(System::Layer * aLayer, void * appState)
Expand All @@ -207,5 +222,16 @@ void ICDManager::OnActiveModeDone(System::Layer * aLayer, void * appState)
pIcdManager->UpdateOperationState(OperationalState::IdleMode);
}
}

void ICDManager::OnTransitionToIdle(System::Layer * aLayer, void * appState)
{
ICDManager * pIcdManager = reinterpret_cast<ICDManager *>(appState);

// OnTransitionToIdle will trigger a report message if reporting is needed, which should extend the active mode until the
// ack for the report is received.
pIcdManager->mTransitionToIdleCalled = true;
pIcdManager->mStateObserver->OnTransitionToIdle();
}

} // namespace app
} // namespace chip
8 changes: 8 additions & 0 deletions src/app/icd/ICDManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ class ICDManager

static void OnIdleModeDone(System::Layer * aLayer, void * appState);
static void OnActiveModeDone(System::Layer * aLayer, void * appState);
/**
* @brief Callback function called shortly before the device enters idle mode to allow checks to be made. This is currently only
* called once to prevent entering in a loop if some events re-trigger this check (for instance if a check for subscription
* before entering idle mode leads to emiting a report, we will re-enter UpdateOperationState and check again for subscription,
* etc.)
*/
static void OnTransitionToIdle(System::Layer * aLayer, void * appState);

private:
// SIT ICDs should have a SlowPollingThreshold shorter than or equal to 15s (spec 9.16.1.5)
Expand All @@ -95,6 +102,7 @@ class ICDManager
PersistentStorageDelegate * mStorage = nullptr;
FabricTable * mFabricTable = nullptr;
ICDStateObserver * mStateObserver = nullptr;
bool mTransitionToIdleCalled = false;
};

} // namespace app
Expand Down
11 changes: 10 additions & 1 deletion src/app/icd/ICDStateObserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,23 @@
*/
#pragma once

#ifndef ICD_SLEEP_TIME_JITTER_MS
#define ICD_SLEEP_TIME_JITTER_MS (CHIP_CONFIG_ICD_IDLE_MODE_INTERVAL * 0.75)
#endif

#ifndef ICD_ACTIVE_TIME_JITTER_MS
#define ICD_ACTIVE_TIME_JITTER_MS 300
#endif

namespace chip {
namespace app {

class ICDStateObserver
{
public:
virtual ~ICDStateObserver() {}
virtual void OnEnterActiveMode() = 0;
virtual void OnEnterActiveMode() = 0;
virtual void OnTransitionToIdle() = 0;
};

} // namespace app
Expand Down
2 changes: 2 additions & 0 deletions src/app/reporting/ReportSchedulerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ ReportSchedulerImpl::ReportSchedulerImpl(TimerDelegate * aTimerDelegate) : Repor
VerifyOrDie(nullptr != mTimerDelegate);
}

void ReportSchedulerImpl::OnTransitionToIdle() {}

/// @brief Method that triggers a report emission on each ReadHandler that is not blocked on its min interval.
/// Each read handler that is not blocked is immediately marked dirty so that it will report as soon as possible.
void ReportSchedulerImpl::OnEnterActiveMode()
Expand Down
1 change: 1 addition & 0 deletions src/app/reporting/ReportSchedulerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class ReportSchedulerImpl : public ReportScheduler

// ICDStateObserver
void OnEnterActiveMode() override;
void OnTransitionToIdle() override;

// ReadHandlerObserver
void OnSubscriptionEstablished(ReadHandler * aReadHandler) final;
Expand Down
13 changes: 13 additions & 0 deletions src/app/reporting/SynchronizedReportSchedulerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ void SynchronizedReportSchedulerImpl::OnReadHandlerDestroyed(ReadHandler * aRead
}
}

void SynchronizedReportSchedulerImpl::OnTransitionToIdle()
{
Timestamp now = mTimerDelegate->GetCurrentMonotonicTimestamp();
uint32_t targetIdleInterval = static_cast<uint32_t>(ICD_SLEEP_TIME_JITTER_MS);
VerifyOrReturn(now >= mTestNextReportTimestamp);
if (((mTestNextReportTimestamp - now) < Seconds16(targetIdleInterval)) && (now > mNextMinTimestamp))
{
// If the next report is due in less than the idle mode interval and we are past the min interval, we can just send it now
CancelReport();
TimerFired();
lpbeliveau-silabs marked this conversation as resolved.
Show resolved Hide resolved
}
}

CHIP_ERROR SynchronizedReportSchedulerImpl::ScheduleReport(Timeout timeout, ReadHandlerNode * node, const Timestamp & now)
{
// Cancel Report if it is currently scheduled
Expand Down
2 changes: 2 additions & 0 deletions src/app/reporting/SynchronizedReportSchedulerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class SynchronizedReportSchedulerImpl : public ReportSchedulerImpl, public Timer
SynchronizedReportSchedulerImpl(TimerDelegate * aTimerDelegate) : ReportSchedulerImpl(aTimerDelegate) {}
~SynchronizedReportSchedulerImpl() override { UnregisterAllHandlers(); }

void OnTransitionToIdle() override;

bool IsReportScheduled();

void TimerFired() override;
Expand Down
1 change: 1 addition & 0 deletions src/app/tests/TestICDManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class TestICDStateObserver : public app::ICDStateObserver
{
public:
void OnEnterActiveMode() {}
void OnTransitionToIdle() {}
};

TestICDStateObserver mICDStateObserver;
Expand Down