diff --git a/config/zephyr/Kconfig b/config/zephyr/Kconfig index 63b9e727d17fbb..b3404c5ef3de08 100644 --- a/config/zephyr/Kconfig +++ b/config/zephyr/Kconfig @@ -108,6 +108,16 @@ config CHIP_OTA_REQUESTOR Device Firmware Upgrade by quering and downloading a new firmware image from an external OTA Provider node. +config CHIP_OPERATIONAL_TIME_SAVE_INTERVAL + int "Interval of saving node operation time to flash in hours unit" + default 10 + range 1 4294967295 + help + Interval in hours with which the node operation time is saved to the flash + memory. Selected value is a trade off between performing frequent saves to know + precisely operation time in case of device reboot and maximizing flash memory + lifetime. + config APP_LINK_WITH_CHIP bool "Link 'app' with Connected Home over IP" default y diff --git a/src/platform/Zephyr/ConfigurationManagerImpl.cpp b/src/platform/Zephyr/ConfigurationManagerImpl.cpp index 7c4f7ab9b095ba..65f95d9c3c3e40 100644 --- a/src/platform/Zephyr/ConfigurationManagerImpl.cpp +++ b/src/platform/Zephyr/ConfigurationManagerImpl.cpp @@ -111,6 +111,22 @@ CHIP_ERROR ConfigurationManagerImpl::StoreRebootCount(uint32_t rebootCount) return WriteConfigValue(ZephyrConfig::kCounterKey_RebootCount, rebootCount); } +CHIP_ERROR ConfigurationManagerImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours) +{ + if (!ZephyrConfig::ConfigValueExists(ZephyrConfig::kCounterKey_TotalOperationalHours)) + { + totalOperationalHours = 0; + return CHIP_NO_ERROR; + } + + return ZephyrConfig::ReadConfigValue(ZephyrConfig::kCounterKey_TotalOperationalHours, totalOperationalHours); +} + +CHIP_ERROR ConfigurationManagerImpl::StoreTotalOperationalHours(uint32_t totalOperationalHours) +{ + return ZephyrConfig::WriteConfigValue(ZephyrConfig::kCounterKey_TotalOperationalHours, totalOperationalHours); +} + void ConfigurationManagerImpl::InitiateFactoryReset() { PlatformMgr().ScheduleWork(DoFactoryReset); diff --git a/src/platform/Zephyr/ConfigurationManagerImpl.h b/src/platform/Zephyr/ConfigurationManagerImpl.h index bcca062af99771..44d66d3ab63e15 100644 --- a/src/platform/Zephyr/ConfigurationManagerImpl.h +++ b/src/platform/Zephyr/ConfigurationManagerImpl.h @@ -38,6 +38,8 @@ class ConfigurationManagerImpl : public Internal::GenericConfigurationManagerImp public: CHIP_ERROR GetRebootCount(uint32_t & rebootCount) override; CHIP_ERROR StoreRebootCount(uint32_t rebootCount) override; + CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours) override; + CHIP_ERROR StoreTotalOperationalHours(uint32_t totalOperationalHours) override; // This returns an instance of this class. static ConfigurationManagerImpl & GetDefaultInstance(); diff --git a/src/platform/Zephyr/DiagnosticDataProviderImpl.cpp b/src/platform/Zephyr/DiagnosticDataProviderImpl.cpp index e627bb5a0d7296..e5f2c03743e09c 100644 --- a/src/platform/Zephyr/DiagnosticDataProviderImpl.cpp +++ b/src/platform/Zephyr/DiagnosticDataProviderImpl.cpp @@ -90,6 +90,37 @@ CHIP_ERROR DiagnosticDataProviderImpl::GetRebootCount(uint16_t & rebootCount) return err; } +CHIP_ERROR DiagnosticDataProviderImpl::GetUpTime(uint64_t & upTime) +{ + System::Clock::Timestamp currentTime = System::SystemClock().GetMonotonicTimestamp(); + System::Clock::Timestamp startTime = PlatformMgrImpl().GetStartTime(); + + if (currentTime >= startTime) + { + upTime = std::chrono::duration_cast(currentTime - startTime).count(); + return CHIP_NO_ERROR; + } + + return CHIP_ERROR_INVALID_TIME; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours) +{ + uint64_t upTimeS; + + ReturnErrorOnFailure(GetUpTime(upTimeS)); + + uint32_t totalHours = 0; + const uint32_t upTimeH = upTimeS / 3600 < UINT32_MAX ? static_cast(upTimeS / 3600) : UINT32_MAX; + const uint32_t deltaTime = upTimeH - PlatformMgrImpl().GetSavedOperationalHoursSinceBoot(); + + ReturnErrorOnFailure(ConfigurationMgr().GetTotalOperationalHours(totalHours)); + + totalOperationalHours = totalHours + deltaTime < UINT32_MAX ? totalHours + deltaTime : UINT32_MAX; + + return CHIP_NO_ERROR; +} + CHIP_ERROR DiagnosticDataProviderImpl::GetBootReason(uint8_t & bootReason) { #if CONFIG_HWINFO diff --git a/src/platform/Zephyr/DiagnosticDataProviderImpl.h b/src/platform/Zephyr/DiagnosticDataProviderImpl.h index 36eeef68422879..05687dcb9832fc 100644 --- a/src/platform/Zephyr/DiagnosticDataProviderImpl.h +++ b/src/platform/Zephyr/DiagnosticDataProviderImpl.h @@ -44,6 +44,8 @@ class DiagnosticDataProviderImpl : public DiagnosticDataProvider CHIP_ERROR GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark) override; CHIP_ERROR GetRebootCount(uint16_t & rebootCount) override; + CHIP_ERROR GetUpTime(uint64_t & upTime) override; + CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours) override; CHIP_ERROR GetBootReason(uint8_t & bootReason) override; CHIP_ERROR GetNetworkInterfaces(NetworkInterface ** netifpp) override; void ReleaseNetworkInterfaces(NetworkInterface * netifp) override; diff --git a/src/platform/Zephyr/PlatformManagerImpl.cpp b/src/platform/Zephyr/PlatformManagerImpl.cpp index 1efda5025fa61c..81a7d12420a787 100644 --- a/src/platform/Zephyr/PlatformManagerImpl.cpp +++ b/src/platform/Zephyr/PlatformManagerImpl.cpp @@ -42,6 +42,8 @@ static K_THREAD_STACK_DEFINE(sChipThreadStack, CHIP_DEVICE_CONFIG_CHIP_TASK_STAC PlatformManagerImpl PlatformManagerImpl::sInstance{ sChipThreadStack }; +static k_timer sOperationalHoursSavingTimer; + #if !CONFIG_NORDIC_SECURITY_BACKEND static int app_entropy_source(void * data, unsigned char * output, size_t len, size_t * olen) { @@ -61,6 +63,36 @@ static int app_entropy_source(void * data, unsigned char * output, size_t len, s } #endif // !CONFIG_NORDIC_SECURITY_BACKEND +void PlatformManagerImpl::OperationalHoursSavingTimerEventHandler(k_timer * timer) +{ + PlatformMgr().ScheduleWork(UpdateOperationalHours); +} + +void PlatformManagerImpl::UpdateOperationalHours(intptr_t arg) +{ + uint64_t upTimeS; + + if (GetDiagnosticDataProvider().GetUpTime(upTimeS) != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Failed to get up time of the node"); + return; + } + + uint32_t totalOperationalHours = 0; + const uint32_t upTimeH = upTimeS / 3600 < UINT32_MAX ? static_cast(upTimeS / 3600) : UINT32_MAX; + const uint32_t deltaTime = upTimeH - sInstance.mSavedOperationalHoursSinceBoot; + + if (ConfigurationMgr().GetTotalOperationalHours(totalOperationalHours) == CHIP_NO_ERROR) + { + ConfigurationMgr().StoreTotalOperationalHours(totalOperationalHours + deltaTime); + sInstance.mSavedOperationalHoursSinceBoot = upTimeH; + } + else + { + ChipLogError(DeviceLayer, "Failed to get total operational hours of the node"); + } +} + CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) { CHIP_ERROR err; @@ -86,9 +118,27 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) err = Internal::GenericPlatformManagerImpl_Zephyr::_InitChipStack(); SuccessOrExit(err); + // Start the timer to periodically save node operational hours. + k_timer_init(&sOperationalHoursSavingTimer, &PlatformManagerImpl::OperationalHoursSavingTimerEventHandler, nullptr); + k_timer_user_data_set(&sOperationalHoursSavingTimer, this); + k_timer_start(&sOperationalHoursSavingTimer, K_HOURS(CONFIG_CHIP_OPERATIONAL_TIME_SAVE_INTERVAL), + K_HOURS(CONFIG_CHIP_OPERATIONAL_TIME_SAVE_INTERVAL)); + + ScheduleWork(OnDeviceBoot, 0); + exit: return err; } +void PlatformManagerImpl::OnDeviceBoot(intptr_t arg) +{ + GeneralDiagnosticsDelegate * generalDiagnosticsDelegate = GetDiagnosticDataProvider().GetGeneralDiagnosticsDelegate(); + + if (generalDiagnosticsDelegate) + { + generalDiagnosticsDelegate->OnDeviceRebooted(); + } +} + } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/Zephyr/PlatformManagerImpl.h b/src/platform/Zephyr/PlatformManagerImpl.h index cdc924029f3847..a4bb23f456e235 100644 --- a/src/platform/Zephyr/PlatformManagerImpl.h +++ b/src/platform/Zephyr/PlatformManagerImpl.h @@ -29,7 +29,7 @@ namespace chip { namespace DeviceLayer { /** - * Concrete implementation of the PlatformManager singleton object for the nRF Connect SDK platforms. + * Concrete implementation of the PlatformManager singleton object for the Zephyr platforms. */ class PlatformManagerImpl final : public PlatformManager, public Internal::GenericPlatformManagerImpl_Zephyr { @@ -46,19 +46,27 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener public: // ===== Platform-specific members that may be accessed directly by the application. - /* none so far */ + System::Clock::Timestamp GetStartTime() { return mStartTime; } + uint32_t GetSavedOperationalHoursSinceBoot() { return mSavedOperationalHoursSinceBoot; } private: // ===== Methods that implement the PlatformManager abstract interface. CHIP_ERROR _InitChipStack(void); + static void OperationalHoursSavingTimerEventHandler(k_timer * timer); + static void UpdateOperationalHours(intptr_t arg); + static void OnDeviceBoot(intptr_t arg); + // ===== Members for internal use by the following friends. friend PlatformManager & PlatformMgr(void); friend PlatformManagerImpl & PlatformMgrImpl(void); friend class Internal::BLEManagerImpl; + System::Clock::Timestamp mStartTime = System::Clock::kZero; + uint32_t mSavedOperationalHoursSinceBoot = 0; + explicit PlatformManagerImpl(ThreadStack & stack) : Internal::GenericPlatformManagerImpl_Zephyr(stack) {} static PlatformManagerImpl sInstance; @@ -79,7 +87,7 @@ inline PlatformManager & PlatformMgr(void) * Returns the platform-specific implementation of the PlatformManager singleton object. * * chip applications can use this to gain access to features of the PlatformManager - * that are specific to the ESP32 platform. + * that are specific to the Zephyr platform. */ inline PlatformManagerImpl & PlatformMgrImpl() { diff --git a/src/platform/Zephyr/ZephyrConfig.cpp b/src/platform/Zephyr/ZephyrConfig.cpp index 9bdbccb80d7c79..395d6374921740 100644 --- a/src/platform/Zephyr/ZephyrConfig.cpp +++ b/src/platform/Zephyr/ZephyrConfig.cpp @@ -73,8 +73,9 @@ const ZephyrConfig::Key ZephyrConfig::kConfigKey_CountryCode = CONFIG_KEY const ZephyrConfig::Key ZephyrConfig::kConfigKey_Breadcrumb = CONFIG_KEY(NAMESPACE_CONFIG "breadcrumb"); // Keys stored in the counters namespace -const ZephyrConfig::Key ZephyrConfig::kCounterKey_RebootCount = CONFIG_KEY(NAMESPACE_COUNTERS "reboot-count"); -const ZephyrConfig::Key ZephyrConfig::kCounterKey_BootReason = CONFIG_KEY(NAMESPACE_COUNTERS "boot-reason"); +const ZephyrConfig::Key ZephyrConfig::kCounterKey_RebootCount = CONFIG_KEY(NAMESPACE_COUNTERS "reboot-count"); +const ZephyrConfig::Key ZephyrConfig::kCounterKey_BootReason = CONFIG_KEY(NAMESPACE_COUNTERS "boot-reason"); +const ZephyrConfig::Key ZephyrConfig::kCounterKey_TotalOperationalHours = CONFIG_KEY(NAMESPACE_COUNTERS "total-operational-hours"); namespace { diff --git a/src/platform/Zephyr/ZephyrConfig.h b/src/platform/Zephyr/ZephyrConfig.h index a43d3bfc368be6..f6a1b23ed921bd 100644 --- a/src/platform/Zephyr/ZephyrConfig.h +++ b/src/platform/Zephyr/ZephyrConfig.h @@ -65,6 +65,7 @@ class ZephyrConfig static const Key kConfigKey_Breadcrumb; static const Key kCounterKey_RebootCount; static const Key kCounterKey_BootReason; + static const Key kCounterKey_TotalOperationalHours; static CHIP_ERROR Init(void);