Skip to content

Commit 8df0fe6

Browse files
Adam-Maciugacarlescufi
authored andcommitted
samples: matter: closure: persistent storage
Added persistent storage to the closure sample The open percentage is saved and restored after reboot Signed-off-by: Adam Maciuga <[email protected]>
1 parent 453731d commit 8df0fe6

File tree

12 files changed

+161
-16
lines changed

12 files changed

+161
-16
lines changed

samples/matter/closure/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ target_sources(app PRIVATE
3737
src/closure_manager.cpp
3838
src/closure_control_endpoint.cpp
3939
src/garage_door_impl.cpp
40+
src/persistent_percent.cpp
4041
)
4142

4243
ncs_configure_data_model()

samples/matter/closure/prj.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,6 @@ CONFIG_USE_SEGGER_RTT=n
5252
# Enable Factory Data feature
5353
CONFIG_CHIP_FACTORY_DATA=y
5454
CONFIG_CHIP_FACTORY_DATA_BUILD=y
55+
56+
#Enable Persistent Storage
57+
CONFIG_NCS_SAMPLE_MATTER_PERSISTENT_STORAGE=y

samples/matter/closure/prj_release.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,6 @@ CONFIG_NCS_SAMPLE_MATTER_WATCHDOG=y
6969
# Enable LTO to decrease the flash usage.
7070
CONFIG_LTO=y
7171
CONFIG_ISR_TABLES_LOCAL_DECLARATION=y
72+
73+
#Enable Persistent Storage
74+
CONFIG_NCS_SAMPLE_MATTER_PERSISTENT_STORAGE=y

samples/matter/closure/src/app_task.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include <app/util/attribute-storage.h>
2222
#include <setup_payload/OnboardingCodesUtil.h>
2323

24+
#include <persistent_storage/persistent_storage.h>
25+
2426
#include <zephyr/logging/log.h>
2527

2628
LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL);
@@ -59,6 +61,10 @@ CHIP_ERROR AppTask::Init()
5961

6062
ReturnErrorOnFailure(sIdentifyCluster.Init());
6163

64+
if (Nrf::GetPersistentStorage().NonSecureInit(&mRootNode) != Nrf::PSErrorCode::Success) {
65+
return CHIP_ERROR_PERSISTED_STORAGE_FAILED;
66+
}
67+
6268
ReturnErrorOnFailure(mClosureManager.Init());
6369
return CHIP_NO_ERROR;
6470
}

samples/matter/closure/src/app_task.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#pragma once
77
#include "closure_manager.h"
88
#include "garage_door_impl.h"
9+
#include <persistent_storage/persistent_storage_common.h>
910

1011
class AppTask {
1112
public:
@@ -20,6 +21,8 @@ class AppTask {
2021
CHIP_ERROR StartApp();
2122

2223
private:
24+
constexpr static auto kAccessPrefix = "cs";
25+
Nrf::PersistentStorageNode mRootNode{ kAccessPrefix, strlen(kAccessPrefix) };
2326
GarageDoorImpl mPhysicalDevice;
2427
ClosureManager mClosureManager;
2528
};

samples/matter/closure/src/closure_manager.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ static Nrf::FiniteMap<TargetPositionEnum, uint16_t, 5> sPositionMapTarget = { {
3535
{ TargetPositionEnum::kMoveToFullyOpen, 0 },
3636
{ TargetPositionEnum::kMoveToPedestrianPosition, 0 },
3737
{ TargetPositionEnum::kMoveToSignaturePosition, 0 },
38-
{ TargetPositionEnum::kMoveToVentilationPosition, 7500 },
38+
{ TargetPositionEnum::kMoveToVentilationPosition, 8000 },
3939
} };
4040

4141
static Nrf::FiniteMap<CurrentPositionEnum, uint16_t, 5> sPositionMapCurr = { {
4242
{ CurrentPositionEnum::kFullyClosed, 10000 },
4343
{ CurrentPositionEnum::kFullyOpened, 0 },
4444
{ CurrentPositionEnum::kOpenedForPedestrian, 0 },
4545
{ CurrentPositionEnum::kOpenedAtSignature, 0 },
46-
{ CurrentPositionEnum::kOpenedForVentilation, 7500 },
46+
{ CurrentPositionEnum::kOpenedForVentilation, 8000 },
4747
} };
4848

4949
static Nrf::FiniteMap<Clusters::Globals::ThreeLevelAutoEnum, uint16_t, 4> sSpeedMap = { {
@@ -91,8 +91,8 @@ ClosureManager::ClosureManager(IPhysicalDevice &device, chip::EndpointId closure
9191

9292
CHIP_ERROR ClosureManager::Init()
9393
{
94-
ReturnErrorOnFailure(mPhysicalDevice.Init());
9594
mPhysicalDevice.SetObserver(this);
95+
ReturnErrorOnFailure(mPhysicalDevice.Init());
9696
DeviceLayer::StackLock lock;
9797

9898
/* Closure endpoints initialization */
@@ -159,6 +159,10 @@ void ClosureManager::OnMovementStopped(uint16_t currentPosition)
159159
LOG_DBG("Attributes updated on movement stopped");
160160
}
161161
}
162+
void ClosureManager::OnSetup(uint16_t currentPosition)
163+
{
164+
mCurrentState.position = MakeOptional(ExactPos2Enum(currentPosition));
165+
}
162166

163167
void ClosureManager::OnMovementUpdate(uint16_t currentPosition, uint16_t timeLeft, bool justStarted)
164168
{

samples/matter/closure/src/closure_manager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class ClosureManager : public IPhysicalDeviceObserver {
7777
chip::Protocols::InteractionModel::Status OnStopCommand();
7878

7979
void OnMovementStopped(uint16_t currentPosition) override;
80+
void OnSetup(uint16_t currentPosition) override;
8081
void OnMovementUpdate(uint16_t currentPosition, uint16_t timeLeft, bool justStarted = false) override;
8182

8283
ElapsedS GetMoveCountdownTime() { return mMoveCountdownTime; }

samples/matter/closure/src/garage_door_impl.cpp

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,21 @@ using namespace chip::DeviceLayer;
1616

1717
static constexpr uint32_t kMoveIntervalMs = 100;
1818

19-
GarageDoorImpl::GarageDoorImpl(const pwm_dt_spec *spec) : mSpec(spec) {}
19+
GarageDoorImpl::GarageDoorImpl(const pwm_dt_spec *spec) : mSpec(spec), mCurrentPosition("cp") {}
2020

2121
CHIP_ERROR GarageDoorImpl::Init()
2222
{
23+
ReturnErrorOnFailure(mCurrentPosition.Load());
24+
mObserver->OnSetup(mCurrentPosition.Get());
25+
2326
if (mPhysicalIndicator.Init(mSpec, 0, 255) != 0) {
2427
LOG_ERR("Cannot initialize the physical indicator");
2528
return CHIP_ERROR_INCORRECT_STATE;
2629
}
30+
uint8_t brightness =
31+
static_cast<uint8_t>((static_cast<uint32_t>(mCurrentPosition.Get()) * 255U + 5000U) / 10000U);
32+
mPhysicalIndicator.InitiateAction(Nrf::PWMDevice::LEVEL_ACTION, 0, &brightness);
33+
2734
return CHIP_NO_ERROR;
2835
}
2936

@@ -43,7 +50,7 @@ CHIP_ERROR GarageDoorImpl::Stop()
4350
{
4451
SystemLayer().CancelTimer(TimerTimeoutCallback, this);
4552
LOG_DBG("Movement stopped");
46-
mObserver->OnMovementStopped(mCurrentPosition);
53+
mObserver->OnMovementStopped(mCurrentPosition.Get());
4754
return CHIP_NO_ERROR;
4855
}
4956

@@ -60,25 +67,26 @@ void GarageDoorImpl::HandleTimer()
6067
uint32_t movePerTick32 = (static_cast<uint32_t>(mSpeed) * kMoveIntervalMs) / 1000U;
6168
uint16_t movePerTick = static_cast<uint16_t>(std::min<uint32_t>(movePerTick32, UINT16_MAX));
6269
uint16_t distanceLeft = 0;
63-
if (mCurrentPosition <= mTargetPosition) {
64-
distanceLeft = mTargetPosition - mCurrentPosition;
70+
71+
if (mCurrentPosition.Get() <= mTargetPosition) {
72+
distanceLeft = mTargetPosition - mCurrentPosition.Get();
6573
if (movePerTick >= distanceLeft) {
6674
finished = true;
67-
mCurrentPosition = mTargetPosition;
75+
mCurrentPosition.Set(mTargetPosition, true);
6876
} else {
69-
mCurrentPosition += movePerTick;
77+
mCurrentPosition.Set(mCurrentPosition.Get() + movePerTick);
7078
}
7179
} else {
72-
distanceLeft = mCurrentPosition - mTargetPosition;
80+
distanceLeft = mCurrentPosition.Get() - mTargetPosition;
7381
if (movePerTick >= distanceLeft) {
7482
finished = true;
75-
mCurrentPosition = mTargetPosition;
83+
mCurrentPosition.Set(mTargetPosition, true);
7684
} else {
77-
mCurrentPosition -= movePerTick;
85+
mCurrentPosition.Set(mCurrentPosition.Get() - movePerTick);
7886
}
7987
}
80-
81-
uint8_t brightness = static_cast<uint8_t>((static_cast<uint32_t>(mCurrentPosition) * 255U + 5000U) / 10000U);
88+
uint8_t brightness =
89+
static_cast<uint8_t>((static_cast<uint32_t>(mCurrentPosition.Get()) * 255U + 5000U) / 10000U);
8290

8391
mPhysicalIndicator.InitiateAction(Nrf::PWMDevice::LEVEL_ACTION, 0, &brightness);
8492

@@ -87,7 +95,7 @@ void GarageDoorImpl::HandleTimer()
8795
} else {
8896
uint32_t timeLeftMs = (static_cast<uint32_t>(distanceLeft) * kMoveIntervalMs) / movePerTick;
8997
uint16_t timeLeftS = static_cast<uint16_t>((timeLeftMs + 999) / 1000); /*ceil*/
90-
mObserver->OnMovementUpdate(mCurrentPosition, timeLeftS, mJustStarted);
98+
mObserver->OnMovementUpdate(mCurrentPosition.Get(), timeLeftS, mJustStarted);
9199
mJustStarted = false;
92100
auto err = SystemLayer().StartTimer(System::Clock::Milliseconds32(kMoveIntervalMs),
93101
TimerTimeoutCallback, this);

samples/matter/closure/src/garage_door_impl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#pragma once
88

9+
#include "persistent_percent.h"
910
#include "physical_device.h"
1011
#include "physical_device_observer.h"
1112
#include "pwm/pwm_device.h"
@@ -30,6 +31,6 @@ class GarageDoorImpl : public IPhysicalDevice {
3031
const pwm_dt_spec *mSpec;
3132
bool mJustStarted = false;
3233
uint16_t mSpeed;
33-
uint16_t mCurrentPosition;
34+
PersistentPercent mCurrentPosition;
3435
uint16_t mTargetPosition;
3536
};
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#include "persistent_percent.h"
8+
9+
#include <cstdlib>
10+
#include <cstring>
11+
#include <persistent_storage/persistent_storage.h>
12+
#include <platform/CHIPDeviceLayer.h>
13+
14+
#include <zephyr/logging/log.h>
15+
16+
LOG_MODULE_DECLARE(persistent_percent, CONFIG_CHIP_APP_LOG_LEVEL);
17+
18+
using namespace chip;
19+
using namespace chip::DeviceLayer;
20+
21+
CHIP_ERROR PersistentPercent::Set(uint16_t newValue, bool forceStore)
22+
{
23+
mValue = newValue;
24+
uint16_t rounded = RoundToStep(newValue);
25+
26+
if (forceStore) {
27+
ReturnErrorOnFailure(Store(mValue));
28+
} else if (rounded != mStored) {
29+
ReturnErrorOnFailure(Store(rounded));
30+
}
31+
return CHIP_NO_ERROR;
32+
}
33+
34+
CHIP_ERROR PersistentPercent::Store(uint16_t val)
35+
{
36+
Nrf::PersistentStorageNode node{ mKey.c_str(), mKey.size() + 1 };
37+
auto err = Nrf::GetPersistentStorage().NonSecureStore(&node, &val, sizeof(val));
38+
39+
if (err == Nrf::PSErrorCode::Success) {
40+
mStored = val;
41+
return CHIP_NO_ERROR;
42+
}
43+
return CHIP_ERROR_PERSISTED_STORAGE_FAILED;
44+
}
45+
46+
CHIP_ERROR PersistentPercent::Load()
47+
{
48+
Nrf::PersistentStorageNode node{ mKey.c_str(), mKey.size() + 1 };
49+
size_t outSize = 0;
50+
auto err = Nrf::GetPersistentStorage().NonSecureLoad(&node, &mValue, sizeof(mValue), outSize);
51+
52+
if (err == Nrf::PSErrorCode::Success) {
53+
mStored = mValue;
54+
return CHIP_NO_ERROR;
55+
}
56+
// Not found, store default
57+
return Store(mValue);
58+
}
59+
60+
uint16_t PersistentPercent::RoundToStep(uint16_t v)
61+
{
62+
uint16_t best = allowed[0];
63+
uint16_t bestDiff = std::abs((int)allowed[0] - (int)v);
64+
65+
for (uint16_t a : allowed) {
66+
uint16_t diff = std::abs((int)a - (int)v);
67+
if (diff < bestDiff) {
68+
best = a;
69+
bestDiff = diff;
70+
}
71+
}
72+
return best;
73+
}

0 commit comments

Comments
 (0)