Skip to content

Commit

Permalink
Implement run time value to the General diagnostics attributes for EF…
Browse files Browse the repository at this point in the history
…R32 platform (#12376)

* EFR32 run time general diagnostic values. Track reboot counts, Retrieve reboot causes

* Complete reboot cause, add GetNetworkInterface, save TotalOperationHours on shutdown
  • Loading branch information
jmartinez-silabs authored and pull[bot] committed Mar 30, 2022
1 parent 68f83f2 commit 1569577
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 4 deletions.
97 changes: 97 additions & 0 deletions src/platform/EFR32/ConfigurationManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <platform/ConfigurationManager.h>
#include <platform/EFR32/EFR32Config.h>

#include "em_rmu.h"

namespace chip {
namespace DeviceLayer {

Expand All @@ -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)
{
Expand All @@ -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)
{
Expand Down
8 changes: 7 additions & 1 deletion src/platform/EFR32/ConfigurationManagerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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);
};

Expand Down
128 changes: 128 additions & 0 deletions src/platform/EFR32/DiagnosticDataProviderImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@

#include <platform/DiagnosticDataProvider.h>
#include <platform/EFR32/DiagnosticDataProviderImpl.h>
#include <platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h>

#include <lwip/tcpip.h>

#include "AppConfig.h"
#include "FreeRTOS.h"

using namespace ::chip::app::Clusters::GeneralDiagnostics;

namespace chip {
namespace DeviceLayer {

Expand All @@ -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
Expand Down Expand Up @@ -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<uint16_t>(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<uint8_t>(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<System::Clock::Seconds64>(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<uint32_t>(upTime / 3600);
return CHIP_NO_ERROR;
}
}

return CHIP_ERROR_INVALID_TIME;
}

CHIP_ERROR DiagnosticDataProviderImpl::GetActiveHardwareFaults(GeneralFaults<kMaxHardwareFaults> & 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<kMaxRadioFaults> & 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<kMaxNetworkFaults> & 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<const char>(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
9 changes: 9 additions & 0 deletions src/platform/EFR32/DiagnosticDataProviderImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<kMaxHardwareFaults> & hardwareFaults) override;
CHIP_ERROR GetActiveRadioFaults(GeneralFaults<kMaxRadioFaults> & radioFaults) override;
CHIP_ERROR GetActiveNetworkFaults(GeneralFaults<kMaxNetworkFaults> & networkFaults) override;
CHIP_ERROR GetNetworkInterfaces(NetworkInterface ** netifpp) override;
void ReleaseNetworkInterfaces(NetworkInterface * netifp) override;
};

} // namespace DeviceLayer
Expand Down
7 changes: 5 additions & 2 deletions src/platform/EFR32/EFR32Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
25 changes: 25 additions & 0 deletions src/platform/EFR32/PlatformManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint32_t>(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<PlatformManagerImpl>::_Shutdown();
}

} // namespace DeviceLayer
} // namespace chip
5 changes: 4 additions & 1 deletion src/platform/EFR32/PlatformManagerImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,22 @@ 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.

friend PlatformManager & PlatformMgr(void);
friend PlatformManagerImpl & PlatformMgrImpl(void);
friend class Internal::BLEManagerImpl;

System::Clock::Timestamp mStartTime = System::Clock::kZero;

static PlatformManagerImpl sInstance;

using Internal::GenericPlatformManagerImpl_FreeRTOS<PlatformManagerImpl>::PostEventFromISR;
Expand Down

0 comments on commit 1569577

Please sign in to comment.