diff --git a/src/platform/ESP32/ConfigurationManagerImpl.cpp b/src/platform/ESP32/ConfigurationManagerImpl.cpp index b3814d72937fa4..0b9822534560ca 100644 --- a/src/platform/ESP32/ConfigurationManagerImpl.cpp +++ b/src/platform/ESP32/ConfigurationManagerImpl.cpp @@ -57,6 +57,7 @@ ConfigurationManagerImpl ConfigurationManagerImpl::sInstance; CHIP_ERROR ConfigurationManagerImpl::_Init() { CHIP_ERROR err; + uint32_t rebootCount; bool failSafeArmed; // Force initialization of NVS namespaces if they doesn't already exist. @@ -67,6 +68,27 @@ CHIP_ERROR ConfigurationManagerImpl::_Init() err = EnsureNamespace(kConfigNamespace_ChipCounters); SuccessOrExit(err); + if (ConfigValueExists(kCounterKey_RebootCount)) + { + err = GetRebootCount(rebootCount); + SuccessOrExit(err); + + err = StoreRebootCount(rebootCount + 1); + SuccessOrExit(err); + } + else + { + // The first boot after factory reset of the Node. + err = StoreRebootCount(1); + SuccessOrExit(err); + } + + if (!ConfigValueExists(kCounterKey_TotalOperationalHours)) + { + err = StoreTotalOperationalHours(0); + SuccessOrExit(err); + } + // Initialize the generic implementation base class. err = Internal::GenericConfigurationManagerImpl::_Init(); SuccessOrExit(err); @@ -100,6 +122,26 @@ CHIP_ERROR ConfigurationManagerImpl::_Init() return err; } +CHIP_ERROR ConfigurationManagerImpl::GetRebootCount(uint32_t & rebootCount) +{ + return ReadConfigValue(kCounterKey_RebootCount, rebootCount); +} + +CHIP_ERROR ConfigurationManagerImpl::StoreRebootCount(uint32_t rebootCount) +{ + return WriteConfigValue(kCounterKey_RebootCount, rebootCount); +} + +CHIP_ERROR ConfigurationManagerImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours) +{ + return ReadConfigValue(kCounterKey_TotalOperationalHours, totalOperationalHours); +} + +CHIP_ERROR ConfigurationManagerImpl::StoreTotalOperationalHours(uint32_t totalOperationalHours) +{ + return WriteConfigValue(kCounterKey_TotalOperationalHours, totalOperationalHours); +} + CHIP_ERROR ConfigurationManagerImpl::_GetPrimaryWiFiMACAddress(uint8_t * buf) { #if CHIP_DEVICE_CONFIG_ENABLE_WIFI diff --git a/src/platform/ESP32/ConfigurationManagerImpl.h b/src/platform/ESP32/ConfigurationManagerImpl.h index 6dc1adc7617de1..ca46c1d36fa699 100644 --- a/src/platform/ESP32/ConfigurationManagerImpl.h +++ b/src/platform/ESP32/ConfigurationManagerImpl.h @@ -50,6 +50,13 @@ class ConfigurationManagerImpl final : public ConfigurationManager, #endif private Internal::ESP32Config { +public: + CHIP_ERROR GetRebootCount(uint32_t & rebootCount); + CHIP_ERROR StoreRebootCount(uint32_t rebootCount); + CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours); + CHIP_ERROR StoreTotalOperationalHours(uint32_t totalOperationalHours); + +private: // Allow the ConfigurationManager interface class to delegate method calls to // the implementation methods provided by this class. friend class ConfigurationManager; @@ -60,7 +67,6 @@ class ConfigurationManagerImpl final : public ConfigurationManager, friend class Internal::GenericConfigurationManagerImpl; #endif -private: // ===== Members that implement the ConfigurationManager public interface. CHIP_ERROR _Init(void); diff --git a/src/platform/ESP32/ESP32Config.cpp b/src/platform/ESP32/ESP32Config.cpp index 7a9a3e61dd9fdf..136097c0b5e02f 100644 --- a/src/platform/ESP32/ESP32Config.cpp +++ b/src/platform/ESP32/ESP32Config.cpp @@ -73,6 +73,11 @@ const ESP32Config::Key ESP32Config::kConfigKey_RegulatoryLocation = { kConfigNam const ESP32Config::Key ESP32Config::kConfigKey_CountryCode = { kConfigNamespace_ChipConfig, "country-code" }; const ESP32Config::Key ESP32Config::kConfigKey_Breadcrumb = { kConfigNamespace_ChipConfig, "breadcrumb" }; +// Keys stored in the Chip-counters namespace +const ESP32Config::Key ESP32Config::kCounterKey_RebootCount = { kConfigNamespace_ChipCounters, "reboot-count" }; +const ESP32Config::Key ESP32Config::kCounterKey_UpTime = { kConfigNamespace_ChipCounters, "up-time" }; +const ESP32Config::Key ESP32Config::kCounterKey_TotalOperationalHours = { kConfigNamespace_ChipCounters, "total-hours" }; + // Prefix used for NVS keys that contain Chip group encryption keys. const char ESP32Config::kGroupKeyNamePrefix[] = "gk-"; diff --git a/src/platform/ESP32/ESP32Config.h b/src/platform/ESP32/ESP32Config.h index ec1e1a00e2b5d9..face2c0f37e1ba 100644 --- a/src/platform/ESP32/ESP32Config.h +++ b/src/platform/ESP32/ESP32Config.h @@ -74,6 +74,9 @@ class ESP32Config static const Key kConfigKey_RegulatoryLocation; static const Key kConfigKey_CountryCode; static const Key kConfigKey_Breadcrumb; + static const Key kCounterKey_RebootCount; + static const Key kCounterKey_UpTime; + static const Key kCounterKey_TotalOperationalHours; static const char kGroupKeyNamePrefix[]; diff --git a/src/platform/ESP32/PlatformManagerImpl.cpp b/src/platform/ESP32/PlatformManagerImpl.cpp index d9666da4e26f60..bbcbe8f3330739 100644 --- a/src/platform/ESP32/PlatformManagerImpl.cpp +++ b/src/platform/ESP32/PlatformManagerImpl.cpp @@ -25,6 +25,7 @@ /* this file behaves like a config.h, comes first */ #include +#include #include #include #include @@ -85,6 +86,7 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, PlatformManagerImpl::HandleESPSystemEvent, NULL); esp_event_handler_register(IP_EVENT, ESP_EVENT_ANY_ID, PlatformManagerImpl::HandleESPSystemEvent, NULL); + mStartTimeMilliseconds = System::SystemClock().GetMonotonicMilliseconds(); // Initialize the ESP WiFi layer. cfg = WIFI_INIT_CONFIG_DEFAULT(); @@ -118,6 +120,31 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) return chip::DeviceLayer::Internal::ESP32Utils::MapError(err); } +CHIP_ERROR PlatformManagerImpl::_Shutdown() +{ + uint64_t upTime = 0; + + if (_GetUpTime(upTime) == CHIP_NO_ERROR) + { + uint32_t totalOperationalHours = 0; + + if (ConfigurationMgrImpl().GetTotalOperationalHours(totalOperationalHours) == CHIP_NO_ERROR) + { + ConfigurationMgrImpl().StoreTotalOperationalHours(totalOperationalHours + static_cast(upTime / 3600)); + } + else + { + ChipLogError(DeviceLayer, "Failed to get total operational hours of the Node"); + } + } + else + { + ChipLogError(DeviceLayer, "Failed to get current uptime since the Node’s last reboot"); + } + + return Internal::GenericPlatformManagerImpl_FreeRTOS::_Shutdown(); +} + CHIP_ERROR PlatformManagerImpl::_GetCurrentHeapFree(uint64_t & currentHeapFree) { currentHeapFree = esp_get_free_heap_size(); @@ -136,6 +163,81 @@ CHIP_ERROR PlatformManagerImpl::_GetCurrentHeapHighWatermark(uint64_t & currentH return CHIP_NO_ERROR; } +CHIP_ERROR PlatformManagerImpl::_GetRebootCount(uint16_t & rebootCount) +{ + uint32_t count = 0; + + CHIP_ERROR err = ConfigurationMgrImpl().GetRebootCount(count); + + if (err == CHIP_NO_ERROR) + { + VerifyOrReturnError(count <= UINT16_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + rebootCount = static_cast(count); + } + + return err; +} + +CHIP_ERROR PlatformManagerImpl::_GetUpTime(uint64_t & upTime) +{ + uint64_t currentTimeMilliseconds = System::SystemClock().GetMonotonicMilliseconds(); + + if (currentTimeMilliseconds >= mStartTimeMilliseconds) + { + upTime = (currentTimeMilliseconds - mStartTimeMilliseconds) / 1000; + return CHIP_NO_ERROR; + } + + return CHIP_ERROR_INVALID_TIME; +} + +CHIP_ERROR PlatformManagerImpl::_GetTotalOperationalHours(uint32_t & totalOperationalHours) +{ + uint64_t upTime = 0; + + if (_GetUpTime(upTime) == CHIP_NO_ERROR) + { + uint32_t totalHours = 0; + if (ConfigurationMgrImpl().GetTotalOperationalHours(totalHours) == CHIP_NO_ERROR) + { + VerifyOrReturnError(upTime / 3600 <= UINT32_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + totalOperationalHours = totalHours + static_cast(upTime / 3600); + return CHIP_NO_ERROR; + } + } + + return CHIP_ERROR_INVALID_TIME; +} + +CHIP_ERROR PlatformManagerImpl::_GetBootReasons(uint8_t & bootReason) +{ + bootReason = EMBER_ZCL_BOOT_REASON_TYPE_UNSPECIFIED; + uint8_t reason; + reason = static_cast(esp_reset_reason()); + if (reason == ESP_RST_UNKNOWN) + { + bootReason = EMBER_ZCL_BOOT_REASON_TYPE_UNSPECIFIED; + } + else if (reason == ESP_RST_POWERON) + { + bootReason = EMBER_ZCL_BOOT_REASON_TYPE_POWER_ON_REBOOT; + } + else if (reason == ESP_RST_BROWNOUT) + { + bootReason = EMBER_ZCL_BOOT_REASON_TYPE_BROWN_OUT_RESET; + } + else if (reason == ESP_RST_SW) + { + bootReason = EMBER_ZCL_BOOT_REASON_TYPE_SOFTWARE_RESET; + } + else if (reason == ESP_RST_INT_WDT) + { + bootReason = EMBER_ZCL_BOOT_REASON_TYPE_SOFTWARE_WATCHDOG_RESET; + /* Reboot can be due to hardware or software watchdog*/ + } + return CHIP_NO_ERROR; +} + CHIP_ERROR PlatformManagerImpl::InitLwIPCoreLock(void) { return Internal::InitLwIPCoreLock(); diff --git a/src/platform/ESP32/PlatformManagerImpl.h b/src/platform/ESP32/PlatformManagerImpl.h index 6ee09023f11fb1..c316fca8e0f9f0 100644 --- a/src/platform/ESP32/PlatformManagerImpl.h +++ b/src/platform/ESP32/PlatformManagerImpl.h @@ -55,15 +55,22 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener // ===== Methods that implement the PlatformManager abstract interface. CHIP_ERROR _InitChipStack(void); + CHIP_ERROR _Shutdown(); CHIP_ERROR _GetCurrentHeapFree(uint64_t & currentHeapFree); CHIP_ERROR _GetCurrentHeapUsed(uint64_t & currentHeapUsed); CHIP_ERROR _GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark); + CHIP_ERROR _GetRebootCount(uint16_t & rebootCount); + CHIP_ERROR _GetUpTime(uint64_t & upTime); + CHIP_ERROR _GetTotalOperationalHours(uint32_t & totalOperationalHours); + CHIP_ERROR _GetBootReasons(uint8_t & bootReasons); // ===== Members for internal use by the following friends. friend PlatformManager & PlatformMgr(void); friend PlatformManagerImpl & PlatformMgrImpl(void); + uint64_t mStartTimeMilliseconds = 0; + static PlatformManagerImpl sInstance; };