blob: 94e0c12e26e64b3d7aa9c65ac62991685270c9d1 [file]
/*
*
* Copyright (c) 2026 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* Provides the implementation of the Device Layer ConfigurationManager object
* for nRF Connect SDK platforms.
*/
#include <platform/nrfconnect/ConfigurationManagerImpl.h>
#include <platform/internal/CHIPDeviceLayerInternal.h>
#include <app/server/Server.h> // nogncheck
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/Zephyr/ZephyrConfig.h>
#include <platform/internal/GenericConfigurationManagerImpl.ipp>
#ifdef CONFIG_CHIP_FACTORY_RESET_ERASE_SETTINGS
#include <zephyr/settings/settings.h>
#if defined(CONFIG_SETTINGS_NVS)
#include <zephyr/fs/nvs.h>
#elif defined(CONFIG_SETTINGS_ZMS) || defined(CONFIG_SETTINGS_ZMS_LEGACY)
#include <zephyr/fs/zms.h>
#endif // CONFIG_SETTINGS_NVS || CONFIG_SETTINGS_ZMS || CONFIG_SETTINGS_ZMS_LEGACY
#endif // CONFIG_CHIP_FACTORY_RESET_ERASE_SETTINGS
#if defined(CONFIG_OPENTHREAD) || defined(CONFIG_NET_L2_OPENTHREAD)
#include <platform/ThreadStackManager.h>
#endif
#ifdef CONFIG_SOC_FLASH_NRF_RADIO_SYNC_MPSL
#include <mpsl/mpsl_lib.h>
#endif // CONFIG_SOC_FLASH_NRF_RADIO_SYNC_MPSL
namespace chip {
namespace DeviceLayer {
using namespace ::chip::DeviceLayer::Internal;
ConfigurationManagerImplNrf & ConfigurationManagerImplNrf::GetDefaultInstance()
{
static ConfigurationManagerImplNrf sInstance;
return sInstance;
}
CHIP_ERROR ConfigurationManagerImplNrf::Init()
{
ReturnErrorOnFailure(GenericConfigurationManagerImpl<ZephyrConfig>::Init());
if (ZephyrConfig::ConfigValueExists(ZephyrConfig::kCounterKey_RebootCount))
{
uint32_t rebootCount;
ReturnErrorOnFailure(GetRebootCount(rebootCount));
// Do not increment reboot count if the value is going to overflow UINT16.
ReturnErrorOnFailure(StoreRebootCount(rebootCount < UINT16_MAX ? rebootCount + 1 : rebootCount));
}
else
{
// The first boot after factory reset of the Node.
ReturnErrorOnFailure(StoreRebootCount(1));
}
return PlatformMgr().AddEventHandler(FactoryResetEventHandler, 0);
}
void ConfigurationManagerImplNrf::FactoryResetEventHandler(const ChipDeviceEvent * event, intptr_t /* arg */)
{
VerifyOrReturn(event->Type == DeviceEventType::kFactoryReset);
ConfigurationManagerImplNrf & instance = GetDefaultInstance();
instance.mFactoryResetScheduled = true;
#ifdef CONFIG_CHIP_FACTORY_RESET_TIME_MEASUREMENT
instance.mFactoryResetStartTime = System::SystemClock().GetMonotonicTimestamp();
#endif // CONFIG_CHIP_FACTORY_RESET_TIME_MEASUREMENT
}
void ConfigurationManagerImplNrf::InitiateFactoryReset()
{
// Removing the persistent storage entries alone leaves the node in an inconsistent state, so
// let the Matter server delete all the fabrics and emit the Leave event first. The server
// announces that with the kFactoryReset event and then calls this method back.
if (!mFactoryResetScheduled)
{
Server::GetInstance().ScheduleFactoryReset();
return;
}
TEMPORARY_RETURN_IGNORED PlatformMgr().ScheduleWork(DoFactoryReset);
}
void ConfigurationManagerImplNrf::DoFactoryReset(intptr_t /* arg */)
{
ChipLogProgress(DeviceLayer, "Performing factory reset");
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
TEMPORARY_RETURN_IGNORED ThreadStackMgr().ClearAllSrpHostAndServices();
#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT
// Lock the Thread stack to avoid unwanted interaction with settings NVS during factory reset.
#if defined(CONFIG_OPENTHREAD) || defined(CONFIG_NET_L2_OPENTHREAD)
ThreadStackMgr().LockThreadStack();
#endif
#ifdef CONFIG_CHIP_FACTORY_RESET_ERASE_SETTINGS
void * storage = nullptr;
int status = settings_storage_get(&storage);
if (status == 0)
{
#if defined(CONFIG_SETTINGS_NVS)
status = nvs_clear(static_cast<nvs_fs *>(storage));
#elif defined(CONFIG_SETTINGS_ZMS) || defined(CONFIG_SETTINGS_ZMS_LEGACY)
status = zms_clear(static_cast<zms_fs *>(storage));
#endif // CONFIG_SETTINGS_NVS || CONFIG_SETTINGS_ZMS || CONFIG_SETTINGS_ZMS_LEGACY
}
if (status)
{
ChipLogError(DeviceLayer, "Factory reset failed: %d", status);
}
#else
ConnectivityMgr().ErasePersistentInfo();
// Suspending MPSL before the bulk of the flash operations speeds the factory reset up, because
// the flash driver no longer waits for the MPSL synchronization on every write. This is only
// needed when the flash driver and MPSL are actually synchronized.
#ifdef CONFIG_SOC_FLASH_NRF_RADIO_SYNC_MPSL
mpsl_lib_uninit();
#endif // CONFIG_SOC_FLASH_NRF_RADIO_SYNC_MPSL
const CHIP_ERROR err = PersistedStorage::KeyValueStoreMgrImpl().DoFactoryReset();
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Factory reset failed: %" CHIP_ERROR_FORMAT, err.Format());
}
#endif // CONFIG_CHIP_FACTORY_RESET_ERASE_SETTINGS
#ifdef CONFIG_CHIP_FACTORY_RESET_TIME_MEASUREMENT
ChipLogProgress(DeviceLayer, "Factory reset completed, it took: %" PRIu64 " ms",
GetDefaultInstance().GetFactoryResetDuration().count());
#endif // CONFIG_CHIP_FACTORY_RESET_TIME_MEASUREMENT
PlatformMgr().Shutdown();
}
#ifdef CONFIG_CHIP_FACTORY_RESET_TIME_MEASUREMENT
System::Clock::Milliseconds64 ConfigurationManagerImplNrf::GetFactoryResetDuration() const
{
const System::Clock::Timestamp currentTime = System::SystemClock().GetMonotonicTimestamp();
VerifyOrReturnValue(currentTime >= mFactoryResetStartTime, System::Clock::Milliseconds64(0));
return std::chrono::duration_cast<System::Clock::Milliseconds64>(currentTime - mFactoryResetStartTime);
}
#endif // CONFIG_CHIP_FACTORY_RESET_TIME_MEASUREMENT
} // namespace DeviceLayer
} // namespace chip