From 156957734ba169718192408371e67b32b209de77 Mon Sep 17 00:00:00 2001 From: jmartinez-silabs <67972863+jmartinez-silabs@users.noreply.github.com> Date: Wed, 1 Dec 2021 09:26:25 -0500 Subject: [PATCH] Implement run time value to the General diagnostics attributes for EFR32 platform (#12376) * EFR32 run time general diagnostic values. Track reboot counts, Retrieve reboot causes * Complete reboot cause, add GetNetworkInterface, save TotalOperationHours on shutdown --- .../EFR32/ConfigurationManagerImpl.cpp | 97 +++++++++++++ src/platform/EFR32/ConfigurationManagerImpl.h | 8 +- .../EFR32/DiagnosticDataProviderImpl.cpp | 128 ++++++++++++++++++ .../EFR32/DiagnosticDataProviderImpl.h | 9 ++ src/platform/EFR32/EFR32Config.h | 7 +- src/platform/EFR32/PlatformManagerImpl.cpp | 25 ++++ src/platform/EFR32/PlatformManagerImpl.h | 5 +- 7 files changed, 275 insertions(+), 4 deletions(-) diff --git a/src/platform/EFR32/ConfigurationManagerImpl.cpp b/src/platform/EFR32/ConfigurationManagerImpl.cpp index b667afc31b7a4b..711e4540191241 100644 --- a/src/platform/EFR32/ConfigurationManagerImpl.cpp +++ b/src/platform/EFR32/ConfigurationManagerImpl.cpp @@ -29,6 +29,8 @@ #include #include +#include "em_rmu.h" + namespace chip { namespace DeviceLayer { @@ -51,6 +53,12 @@ CHIP_ERROR ConfigurationManagerImpl::Init() // TODO: Initialize the global GroupKeyStore object here (#1626) + IncreaseBootCount(); + // It is possible to configure the possible reset sources with RMU_ResetControl + // In this case, we keep Reset control at default setting + rebootCause = RMU_ResetCauseGet(); + RMU_ResetCauseClear(); + // If the fail-safe was armed when the device last shutdown, initiate a factory reset. if (GetFailSafeArmed(failSafeArmed) == CHIP_NO_ERROR && failSafeArmed) { @@ -74,6 +82,95 @@ void ConfigurationManagerImpl::InitiateFactoryReset() PlatformMgr().ScheduleWork(DoFactoryReset); } +CHIP_ERROR ConfigurationManagerImpl::GetRebootCount(uint32_t & rebootCount) +{ + return EFR32Config::ReadConfigValue(EFR32Config::kConfigKey_BootCount, rebootCount); +} + +CHIP_ERROR ConfigurationManagerImpl::IncreaseBootCount(void) +{ + uint32_t bootCount = 0; + + if (EFR32Config::ConfigValueExists(EFR32Config::kConfigKey_BootCount)) + { + GetRebootCount(bootCount); + } + + return EFR32Config::WriteConfigValue(EFR32Config::kConfigKey_BootCount, bootCount + 1); +} + +uint32_t ConfigurationManagerImpl::GetBootReason(void) +{ + // rebootCause is obtained at bootup. + uint32_t matterBootCause; +#if defined(_SILICON_LABS_32B_SERIES_1) + if (rebootCause & RMU_RSTCAUSE_PORST || rebootCause & RMU_RSTCAUSE_EXTRST) // PowerOn or External pin reset + { + matterBootCause = EMBER_ZCL_BOOT_REASON_TYPE_POWER_ON_REBOOT; + } + else if (rebootCause & RMU_RSTCAUSE_AVDDBOD || rebootCause & RMU_RSTCAUSE_DVDDBOD || rebootCause & RMU_RSTCAUSE_DECBOD) + { + matterBootCause = EMBER_ZCL_BOOT_REASON_TYPE_BROWN_OUT_RESET; + } + else if (rebootCause & RMU_RSTCAUSE_SYSREQRST) + { + matterBootCause = EMBER_ZCL_BOOT_REASON_TYPE_SOFTWARE_RESET; + } + else if (rebootCause & RMU_RSTCAUSE_WDOGRST) + { + matterBootCause = EMBER_ZCL_BOOT_REASON_TYPE_SOFTWARE_WATCHDOG_RESET; + } + else + { + matterBootCause = EMBER_ZCL_BOOT_REASON_TYPE_UNSPECIFIED; + } + // Not tracked HARDWARE_WATCHDOG_RESET && SOFTWARE_UPDATE_COMPLETED +#elif defined(_SILICON_LABS_32B_SERIES_2) + if (rebootCause & EMU_RSTCAUSE_POR || rebootCause & EMU_RSTCAUSE_PIN) // PowerOn or External pin reset + { + matterBootCause = EMBER_ZCL_BOOT_REASON_TYPE_POWER_ON_REBOOT; + } + else if (rebootCause & EMU_RSTCAUSE_AVDDBOD || rebootCause & EMU_RSTCAUSE_DVDDBOD || rebootCause & EMU_RSTCAUSE_DECBOD || + rebootCause & EMU_RSTCAUSE_VREGIN || rebootCause & EMU_RSTCAUSE_IOVDD0BOD || rebootCause & EMU_RSTCAUSE_DVDDLEBOD) + { + matterBootCause = EMBER_ZCL_BOOT_REASON_TYPE_BROWN_OUT_RESET; + } + else if (rebootCause & EMU_RSTCAUSE_SYSREQ) + { + matterBootCause = EMBER_ZCL_BOOT_REASON_TYPE_SOFTWARE_RESET; + } + else if (rebootCause & EMU_RSTCAUSE_WDOG0 || rebootCause & EMU_RSTCAUSE_WDOG1) + { + matterBootCause = EMBER_ZCL_BOOT_REASON_TYPE_SOFTWARE_WATCHDOG_RESET; + } + else + { + matterBootCause = EMBER_ZCL_BOOT_REASON_TYPE_UNSPECIFIED; + } + // Not tracked HARDWARE_WATCHDOG_RESET && SOFTWARE_UPDATE_COMPLETED +#else + matterBootCause = EMBER_ZCL_BOOT_REASON_TYPE_UNSPECIFIED; +#endif + + return matterBootCause; +} + +CHIP_ERROR ConfigurationManagerImpl::GetTotalOperationalHours(uint32_t & totalOperationalHours) +{ + if (!EFR32Config::ConfigValueExists(EFR32Config::kConfigKey_TotalOperationalHours)) + { + totalOperationalHours = 0; + return CHIP_NO_ERROR; + } + + return EFR32Config::ReadConfigValue(EFR32Config::kConfigKey_TotalOperationalHours, totalOperationalHours); +} + +CHIP_ERROR ConfigurationManagerImpl::StoreTotalOperationalHours(uint32_t totalOperationalHours) +{ + return EFR32Config::WriteConfigValue(EFR32Config::kConfigKey_TotalOperationalHours, totalOperationalHours); +} + CHIP_ERROR ConfigurationManagerImpl::ReadPersistedStorageValue(::chip::Platform::PersistedStorage::Key persistedStorageKey, uint32_t & value) { diff --git a/src/platform/EFR32/ConfigurationManagerImpl.h b/src/platform/EFR32/ConfigurationManagerImpl.h index 34037e17cfd67e..a638abc425f5f0 100644 --- a/src/platform/EFR32/ConfigurationManagerImpl.h +++ b/src/platform/EFR32/ConfigurationManagerImpl.h @@ -40,6 +40,12 @@ class ConfigurationManagerImpl : public Internal::GenericConfigurationManagerImp // This returns an instance of this class. static ConfigurationManagerImpl & GetDefaultInstance(); + uint32_t GetBootReason(void); + CHIP_ERROR GetRebootCount(uint32_t & rebootCount); + CHIP_ERROR IncreaseBootCount(void); + CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours); + CHIP_ERROR StoreTotalOperationalHours(uint32_t totalOperationalHours); + private: // ===== Members that implement the ConfigurationManager public interface. @@ -67,7 +73,7 @@ class ConfigurationManagerImpl : public Internal::GenericConfigurationManagerImp void RunConfigUnitTest(void) override; // ===== Private members reserved for use by this class only. - + uint32_t rebootCause; static void DoFactoryReset(intptr_t arg); }; diff --git a/src/platform/EFR32/DiagnosticDataProviderImpl.cpp b/src/platform/EFR32/DiagnosticDataProviderImpl.cpp index cdb3964a0b1c9c..e04a34057f8f4b 100644 --- a/src/platform/EFR32/DiagnosticDataProviderImpl.cpp +++ b/src/platform/EFR32/DiagnosticDataProviderImpl.cpp @@ -25,12 +25,15 @@ #include #include +#include #include #include "AppConfig.h" #include "FreeRTOS.h" +using namespace ::chip::app::Clusters::GeneralDiagnostics; + namespace chip { namespace DeviceLayer { @@ -40,6 +43,7 @@ DiagnosticDataProviderImpl & DiagnosticDataProviderImpl::GetDefaultInstance() return sInstance; } +// Software Diagnostics Getters /* * The following Heap stats are compiled values done by the FreeRTOS Heap4 implementation. * See /examples/platform/efr32/heap_4_silabs.c @@ -77,5 +81,129 @@ CHIP_ERROR DiagnosticDataProviderImpl::GetCurrentHeapHighWatermark(uint64_t & cu return CHIP_NO_ERROR; } +// General Diagnostics Getters + +CHIP_ERROR DiagnosticDataProviderImpl::GetRebootCount(uint16_t & rebootCount) +{ + uint32_t count = 0; + CHIP_ERROR err = ConfigurationMgr().GetRebootCount(count); + + if (err == CHIP_NO_ERROR) + { + VerifyOrReturnError(count <= UINT16_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + rebootCount = static_cast(count); + } + + return err; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetBootReason(uint8_t & bootReason) +{ + uint32_t reason = 0; + CHIP_ERROR err = ConfigurationMgr().GetBootReason(reason); + + if (err == CHIP_NO_ERROR) + { + VerifyOrReturnError(reason <= UINT8_MAX, CHIP_ERROR_INVALID_INTEGER_VALUE); + bootReason = static_cast(reason); + } + + 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 upTime = 0; + + if (GetUpTime(upTime) == CHIP_NO_ERROR) + { + uint32_t totalHours = 0; + if (ConfigurationMgr().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 DiagnosticDataProviderImpl::GetActiveHardwareFaults(GeneralFaults & hardwareFaults) +{ +#if CHIP_CONFIG_TEST + ReturnErrorOnFailure(hardwareFaults.add(EMBER_ZCL_HARDWARE_FAULT_TYPE_RADIO)); + ReturnErrorOnFailure(hardwareFaults.add(EMBER_ZCL_HARDWARE_FAULT_TYPE_SENSOR)); + ReturnErrorOnFailure(hardwareFaults.add(EMBER_ZCL_HARDWARE_FAULT_TYPE_POWER_SOURCE)); + ReturnErrorOnFailure(hardwareFaults.add(EMBER_ZCL_HARDWARE_FAULT_TYPE_USER_INTERFACE_FAULT)); +#endif + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetActiveRadioFaults(GeneralFaults & radioFaults) +{ +#if CHIP_CONFIG_TEST + ReturnErrorOnFailure(radioFaults.add(EMBER_ZCL_RADIO_FAULT_TYPE_THREAD_FAULT)); + ReturnErrorOnFailure(radioFaults.add(EMBER_ZCL_RADIO_FAULT_TYPE_BLE_FAULT)); +#endif + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetActiveNetworkFaults(GeneralFaults & networkFaults) +{ +#if CHIP_CONFIG_TEST + ReturnErrorOnFailure(networkFaults.add(EMBER_ZCL_NETWORK_FAULT_TYPE_HARDWARE_FAILURE)); + ReturnErrorOnFailure(networkFaults.add(EMBER_ZCL_NETWORK_FAULT_TYPE_NETWORK_JAMMED)); + ReturnErrorOnFailure(networkFaults.add(EMBER_ZCL_NETWORK_FAULT_TYPE_CONNECTION_FAILED)); +#endif + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DiagnosticDataProviderImpl::GetNetworkInterfaces(NetworkInterface ** netifpp) +{ + NetworkInterface * ifp = new NetworkInterface(); + + const char * threadNetworkName = otThreadGetNetworkName(ThreadStackMgrImpl().OTInstance()); + ifp->name = Span(threadNetworkName, strlen(threadNetworkName)); + ifp->fabricConnected = true; + ifp->offPremiseServicesReachableIPv4 = false; + ifp->offPremiseServicesReachableIPv6 = false; + ifp->type = InterfaceType::EMBER_ZCL_INTERFACE_TYPE_THREAD; + + uint8_t macBuffer[ConfigurationManager::kPrimaryMACAddressLength]; + ConfigurationMgr().GetPrimary802154MACAddress(macBuffer); + ifp->hardwareAddress = ByteSpan(macBuffer, ConfigurationManager::kPrimaryMACAddressLength); + + *netifpp = ifp; + return CHIP_NO_ERROR; +} + +void DiagnosticDataProviderImpl::ReleaseNetworkInterfaces(NetworkInterface * netifp) +{ + while (netifp) + { + NetworkInterface * del = netifp; + netifp = netifp->Next; + delete del; + } +} + } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/EFR32/DiagnosticDataProviderImpl.h b/src/platform/EFR32/DiagnosticDataProviderImpl.h index 6505cf5eedff17..f2618e0fae6d80 100644 --- a/src/platform/EFR32/DiagnosticDataProviderImpl.h +++ b/src/platform/EFR32/DiagnosticDataProviderImpl.h @@ -42,6 +42,15 @@ class DiagnosticDataProviderImpl : public DiagnosticDataProvider CHIP_ERROR GetCurrentHeapFree(uint64_t & currentHeapFree) override; CHIP_ERROR GetCurrentHeapUsed(uint64_t & currentHeapUsed) override; CHIP_ERROR GetCurrentHeapHighWatermark(uint64_t & currentHeapHighWatermark) override; + CHIP_ERROR GetRebootCount(uint16_t & rebootCount) override; + CHIP_ERROR GetBootReason(uint8_t & bootReason) override; + CHIP_ERROR GetUpTime(uint64_t & upTime) override; + CHIP_ERROR GetTotalOperationalHours(uint32_t & totalOperationalHours) override; + CHIP_ERROR GetActiveHardwareFaults(GeneralFaults & hardwareFaults) override; + CHIP_ERROR GetActiveRadioFaults(GeneralFaults & radioFaults) override; + CHIP_ERROR GetActiveNetworkFaults(GeneralFaults & networkFaults) override; + CHIP_ERROR GetNetworkInterfaces(NetworkInterface ** netifpp) override; + void ReleaseNetworkInterfaces(NetworkInterface * netifp) override; }; } // namespace DeviceLayer diff --git a/src/platform/EFR32/EFR32Config.h b/src/platform/EFR32/EFR32Config.h index a00bd79b335f34..5331c85b30e2b8 100644 --- a/src/platform/EFR32/EFR32Config.h +++ b/src/platform/EFR32/EFR32Config.h @@ -95,8 +95,11 @@ class EFR32Config static constexpr Key kConfigKey_CountryCode = EFR32ConfigKey(kChipConfig_KeyBase, 0x0A); static constexpr Key kConfigKey_Breadcrumb = EFR32ConfigKey(kChipConfig_KeyBase, 0x0B); - static constexpr Key kConfigKey_GroupKeyBase = EFR32ConfigKey(kChipConfig_KeyBase, 0x0C); - static constexpr Key kConfigKey_GroupKeyMax = EFR32ConfigKey(kChipConfig_KeyBase, 0x1B); // Allows 16 Group Keys to be created. + static constexpr Key kConfigKey_BootCount = EFR32ConfigKey(kChipCounter_KeyBase, 0x0C); + static constexpr Key kConfigKey_TotalOperationalHours = EFR32ConfigKey(kChipCounter_KeyBase, 0x0D); + + static constexpr Key kConfigKey_GroupKeyBase = EFR32ConfigKey(kChipConfig_KeyBase, 0x0E); + static constexpr Key kConfigKey_GroupKeyMax = EFR32ConfigKey(kChipConfig_KeyBase, 0x1D); // Allows 16 Group Keys to be created. // Set key id limits for each group. static constexpr Key kMinConfigKey_ChipFactory = EFR32ConfigKey(kChipFactory_KeyBase, 0x00); diff --git a/src/platform/EFR32/PlatformManagerImpl.cpp b/src/platform/EFR32/PlatformManagerImpl.cpp index 764cf70075ffab..790bf23da7ecca 100644 --- a/src/platform/EFR32/PlatformManagerImpl.cpp +++ b/src/platform/EFR32/PlatformManagerImpl.cpp @@ -60,5 +60,30 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) return err; } +CHIP_ERROR PlatformManagerImpl::_Shutdown() +{ + uint64_t upTime = 0; + + if (GetDiagnosticDataProvider().GetUpTime(upTime) == CHIP_NO_ERROR) + { + uint32_t totalOperationalHours = 0; + + if (ConfigurationMgr().GetTotalOperationalHours(totalOperationalHours) == CHIP_NO_ERROR) + { + ConfigurationMgr().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(); +} + } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/EFR32/PlatformManagerImpl.h b/src/platform/EFR32/PlatformManagerImpl.h index 2f7de1d6e5825f..63a3df6fc03eb8 100644 --- a/src/platform/EFR32/PlatformManagerImpl.h +++ b/src/platform/EFR32/PlatformManagerImpl.h @@ -47,12 +47,13 @@ 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; } private: // ===== Methods that implement the PlatformManager abstract interface. CHIP_ERROR _InitChipStack(void); + CHIP_ERROR _Shutdown(void); // ===== Members for internal use by the following friends. @@ -60,6 +61,8 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener friend PlatformManagerImpl & PlatformMgrImpl(void); friend class Internal::BLEManagerImpl; + System::Clock::Timestamp mStartTime = System::Clock::kZero; + static PlatformManagerImpl sInstance; using Internal::GenericPlatformManagerImpl_FreeRTOS::PostEventFromISR;