Skip to content

Commit 77d0df9

Browse files
yufengwangcabzbarsky-apple
authored andcommitted
[linux] Implement reading/writing UserLabelList from/to persistent storage (#16975)
* Implment reading/writing user labelList from/to persistent storage * Add userLabel yaml test * Address review comments * Update src/platform/Linux/DeviceInfoProviderImpl.cpp Co-authored-by: Boris Zbarsky <[email protected]> * Update src/platform/Linux/DeviceInfoProviderImpl.cpp Co-authored-by: Boris Zbarsky <[email protected]> * Update src/platform/Linux/DeviceInfoProviderImpl.cpp Co-authored-by: Boris Zbarsky <[email protected]> * Update test case Co-authored-by: Boris Zbarsky <[email protected]>
1 parent 7e883fa commit 77d0df9

File tree

9 files changed

+493
-58
lines changed

9 files changed

+493
-58
lines changed

.github/workflows/tests.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ jobs:
187187
./scripts/run_in_build_env.sh \
188188
"./scripts/tests/run_test_suite.py \
189189
--chip-tool ./out/darwin-x64-chip-tool${CHIP_TOOL_VARIANT}-${BUILD_VARIANT}/chip-tool \
190-
--target-skip-glob '{TestGroupMessaging}' \
190+
--target-skip-glob '{TestGroupMessaging,TestUserLabelCluster}' \
191191
run \
192192
--iterations 1 \
193193
--all-clusters-app ./out/darwin-x64-all-clusters-${BUILD_VARIANT}/chip-all-clusters-app \

examples/chip-tool/templates/tests/tests.js

+1
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ function getTests()
547547
'TestModeSelectCluster',
548548
'TestSystemCommands',
549549
'TestBinding',
550+
'TestUserLabelCluster',
550551
];
551552

552553
const MultiAdmin = [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Copyright (c) 2022 Project CHIP Authors
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: User Label Cluster Tests
16+
17+
config:
18+
nodeId: 0x12344321
19+
cluster: "User Label"
20+
endpoint: 0
21+
discriminator:
22+
type: INT16U
23+
defaultValue: 3840
24+
25+
tests:
26+
- label: "Wait for the commissioned device to be retrieved"
27+
cluster: "DelayCommands"
28+
command: "WaitForCommissionee"
29+
arguments:
30+
values:
31+
- name: "nodeId"
32+
value: nodeId
33+
34+
- label: "Clear User Label List"
35+
command: "writeAttribute"
36+
attribute: "label list"
37+
arguments:
38+
value: []
39+
40+
- label: "Read User Label List"
41+
command: "readAttribute"
42+
attribute: "label list"
43+
response:
44+
value: []
45+
46+
- label: "Write User Label List"
47+
command: "writeAttribute"
48+
attribute: "label list"
49+
arguments:
50+
value:
51+
[
52+
{ label: "room", value: "bedroom 2" },
53+
{ label: "orientation", value: "North" },
54+
{ label: "floor", value: "5" },
55+
{ label: "direction", value: "up" },
56+
]
57+
58+
- label: "Reboot target device"
59+
cluster: "SystemCommands"
60+
command: "Reboot"
61+
arguments:
62+
values:
63+
- name: "discriminator"
64+
value: discriminator
65+
66+
- label: "Wait for the commissioned device to be retrieved"
67+
cluster: "DelayCommands"
68+
command: "WaitForCommissionee"
69+
arguments:
70+
values:
71+
- name: "nodeId"
72+
value: nodeId
73+
74+
- label: "Verify"
75+
command: "readAttribute"
76+
attribute: "label list"
77+
response:
78+
value:
79+
[
80+
{ label: "room", value: "bedroom 2" },
81+
{ label: "orientation", value: "North" },
82+
{ label: "floor", value: "5" },
83+
{ label: "direction", value: "up" },
84+
]

src/lib/support/DefaultStorageKeyAllocator.h

+4
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ class DefaultStorageKeyAllocator
7676
const char * GroupDataCounter() { return Format("g/gdc"); }
7777
const char * GroupControlCounter() { return Format("g/gcc"); }
7878

79+
// Device Information Provider
80+
const char * UserLabelLengthKey(EndpointId endpoint) { return Format("g/userlbl/%x", endpoint); }
81+
const char * UserLabelIndexKey(EndpointId endpoint, uint32_t index) { return Format("g/userlbl/%x/%" PRIx32, endpoint, index); }
82+
7983
// Group Data Provider
8084

8185
// List of fabric indices that have endpoint-to-group associations defined.

src/platform/Linux/CHIPLinuxStorage.h

+7
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@
4848
#define LOCALSTATEDIR "/tmp"
4949
#endif
5050

51+
#ifndef DEVICEINFODIR
52+
#define DEVICEINFODIR "/tmp"
53+
#endif
54+
5155
#define CHIP_DEFAULT_FACTORY_PATH \
5256
FATCONFDIR "/" \
5357
"chip_factory.ini"
@@ -57,6 +61,9 @@
5761
#define CHIP_DEFAULT_DATA_PATH \
5862
LOCALSTATEDIR "/" \
5963
"chip_counters.ini"
64+
#define CHIP_DEVICE_INFO_PATH \
65+
DEVICEINFODIR "/" \
66+
"chip_device_info.ini"
6067

6168
namespace chip {
6269
namespace DeviceLayer {

src/platform/Linux/DeviceInfoProviderImpl.cpp

+59-50
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <lib/core/CHIPTLV.h>
1919
#include <lib/support/CHIPMemString.h>
2020
#include <lib/support/CodeUtils.h>
21+
#include <lib/support/DefaultStorageKeyAllocator.h>
2122
#include <platform/Linux/DeviceInfoProviderImpl.h>
2223
#include <platform/internal/CHIPDeviceLayerInternal.h>
2324

@@ -27,6 +28,16 @@
2728
namespace chip {
2829
namespace DeviceLayer {
2930

31+
namespace {
32+
constexpr TLV::Tag kLabelNameTag = TLV::ContextTag(0);
33+
constexpr TLV::Tag kLabelValueTag = TLV::ContextTag(1);
34+
} // anonymous namespace
35+
36+
CHIP_ERROR DeviceInfoProviderImpl::Init()
37+
{
38+
return mStorage.Init(CHIP_DEVICE_INFO_PATH);
39+
}
40+
3041
DeviceInfoProviderImpl & DeviceInfoProviderImpl::GetDefaultInstance()
3142
{
3243
static DeviceInfoProviderImpl sInstance;
@@ -107,23 +118,33 @@ bool DeviceInfoProviderImpl::FixedLabelIteratorImpl::Next(FixedLabelType & outpu
107118

108119
CHIP_ERROR DeviceInfoProviderImpl::SetUserLabelLength(EndpointId endpoint, size_t val)
109120
{
110-
// TODO:: store the user label count.
111-
return CHIP_ERROR_NOT_IMPLEMENTED;
121+
DefaultStorageKeyAllocator keyAlloc;
122+
123+
return mStorage.WriteValue(keyAlloc.UserLabelLengthKey(endpoint), val);
112124
}
113125

114126
CHIP_ERROR DeviceInfoProviderImpl::GetUserLabelLength(EndpointId endpoint, size_t & val)
115127
{
116-
// TODO:: read the user label count. temporarily return the size of hardcoded labelList.
117-
val = 4;
128+
DefaultStorageKeyAllocator keyAlloc;
118129

119-
return CHIP_NO_ERROR;
130+
return mStorage.ReadValue(keyAlloc.UserLabelLengthKey(endpoint), val);
120131
}
121132

122133
CHIP_ERROR DeviceInfoProviderImpl::SetUserLabelAt(EndpointId endpoint, size_t index, const UserLabelType & userLabel)
123134
{
124-
// TODO:: store the user labelList, and read back stored user labelList if it has been set.
125-
// Add yaml test to verify this.
126-
return CHIP_ERROR_NOT_IMPLEMENTED;
135+
DefaultStorageKeyAllocator keyAlloc;
136+
uint8_t buf[UserLabelTLVMaxSize()];
137+
TLV::TLVWriter writer;
138+
writer.Init(buf);
139+
140+
TLV::TLVType outerType;
141+
ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerType));
142+
ReturnErrorOnFailure(writer.PutString(kLabelNameTag, userLabel.label));
143+
ReturnErrorOnFailure(writer.PutString(kLabelValueTag, userLabel.value));
144+
ReturnErrorOnFailure(writer.EndContainer(outerType));
145+
ReturnErrorOnFailure(mStorage.WriteValueBin(keyAlloc.UserLabelIndexKey(endpoint, index), buf, writer.GetLengthWritten()));
146+
147+
return mStorage.Commit();
127148
}
128149

129150
DeviceInfoProvider::UserLabelIterator * DeviceInfoProviderImpl::IterateUserLabel(EndpointId endpoint)
@@ -143,57 +164,45 @@ DeviceInfoProviderImpl::UserLabelIteratorImpl::UserLabelIteratorImpl(DeviceInfoP
143164

144165
bool DeviceInfoProviderImpl::UserLabelIteratorImpl::Next(UserLabelType & output)
145166
{
146-
// TODO:: get the user labelList from persistent storage, temporarily, use the following
147-
// hardcoded labelList on all endpoints.
148167
CHIP_ERROR err = CHIP_NO_ERROR;
149168

150-
const char * labelPtr = nullptr;
151-
const char * valuePtr = nullptr;
152-
153169
VerifyOrReturnError(mIndex < mTotal, false);
154170

155-
switch (mIndex)
156-
{
157-
case 0:
158-
labelPtr = "room";
159-
valuePtr = "bedroom 2";
160-
break;
161-
case 1:
162-
labelPtr = "orientation";
163-
valuePtr = "North";
164-
break;
165-
case 2:
166-
labelPtr = "floor";
167-
valuePtr = "2";
168-
break;
169-
case 3:
170-
labelPtr = "direction";
171-
valuePtr = "up";
172-
break;
173-
default:
174-
err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
175-
break;
176-
}
171+
DefaultStorageKeyAllocator keyAlloc;
172+
uint8_t buf[UserLabelTLVMaxSize()];
173+
size_t outLen;
174+
err = mProvider.mStorage.ReadValueBin(keyAlloc.UserLabelIndexKey(mEndpoint, mIndex), buf, sizeof(buf), outLen);
175+
VerifyOrReturnError(err == CHIP_NO_ERROR, false);
177176

178-
if (err == CHIP_NO_ERROR)
179-
{
180-
VerifyOrReturnError(std::strlen(labelPtr) <= kMaxLabelNameLength, false);
181-
VerifyOrReturnError(std::strlen(valuePtr) <= kMaxLabelValueLength, false);
177+
TLV::ContiguousBufferTLVReader reader;
178+
reader.Init(buf);
179+
err = reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag());
180+
VerifyOrReturnError(err == CHIP_NO_ERROR, false);
182181

183-
Platform::CopyString(mUserLabelNameBuf, kMaxLabelNameLength + 1, labelPtr);
184-
Platform::CopyString(mUserLabelValueBuf, kMaxLabelValueLength + 1, valuePtr);
182+
TLV::TLVType containerType;
183+
VerifyOrReturnError(reader.EnterContainer(containerType) == CHIP_NO_ERROR, false);
185184

186-
output.label = CharSpan::fromCharString(mUserLabelNameBuf);
187-
output.value = CharSpan::fromCharString(mUserLabelValueBuf);
185+
chip::CharSpan label;
186+
chip::CharSpan value;
188187

189-
mIndex++;
188+
VerifyOrReturnError(reader.Next(kLabelNameTag) == CHIP_NO_ERROR, false);
189+
VerifyOrReturnError(reader.Get(label) == CHIP_NO_ERROR, false);
190190

191-
return true;
192-
}
193-
else
194-
{
195-
return false;
196-
}
191+
VerifyOrReturnError(reader.Next(kLabelValueTag) == CHIP_NO_ERROR, false);
192+
VerifyOrReturnError(reader.Get(value) == CHIP_NO_ERROR, false);
193+
194+
VerifyOrReturnError(reader.VerifyEndOfContainer() == CHIP_NO_ERROR, false);
195+
VerifyOrReturnError(reader.ExitContainer(containerType) == CHIP_NO_ERROR, false);
196+
197+
Platform::CopyString(mUserLabelNameBuf, label);
198+
Platform::CopyString(mUserLabelValueBuf, value);
199+
200+
output.label = CharSpan::fromCharString(mUserLabelNameBuf);
201+
output.value = CharSpan::fromCharString(mUserLabelValueBuf);
202+
203+
mIndex++;
204+
205+
return true;
197206
}
198207

199208
DeviceInfoProvider::SupportedLocalesIterator * DeviceInfoProviderImpl::IterateSupportedLocales()

src/platform/Linux/DeviceInfoProviderImpl.h

+16
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
*/
1717
#pragma once
1818

19+
#include <lib/support/EnforceFormat.h>
1920
#include <platform/DeviceInfoProvider.h>
21+
#include <platform/Linux/CHIPLinuxStorage.h>
2022

2123
namespace chip {
2224
namespace DeviceLayer {
@@ -27,6 +29,15 @@ class DeviceInfoProviderImpl : public DeviceInfoProvider
2729
DeviceInfoProviderImpl() = default;
2830
~DeviceInfoProviderImpl() override {}
2931

32+
/**
33+
* Initialize the DeviceInfoProvider, including possibly any persistent
34+
* data store initialization done by the implementation. Must be called once
35+
* before any other API succeeds.
36+
*
37+
* @retval #CHIP_NO_ERROR on success
38+
*/
39+
CHIP_ERROR Init();
40+
3041
// Iterators
3142
FixedLabelIterator * IterateFixedLabel(EndpointId endpoint) override;
3243
UserLabelIterator * IterateUserLabel(EndpointId endpoint) override;
@@ -96,6 +107,11 @@ class DeviceInfoProviderImpl : public DeviceInfoProvider
96107
CHIP_ERROR SetUserLabelLength(EndpointId endpoint, size_t val) override;
97108
CHIP_ERROR GetUserLabelLength(EndpointId endpoint, size_t & val) override;
98109
CHIP_ERROR SetUserLabelAt(EndpointId endpoint, size_t index, const UserLabelType & userLabel) override;
110+
111+
private:
112+
DeviceLayer::Internal::ChipLinuxStorage mStorage;
113+
114+
static constexpr size_t UserLabelTLVMaxSize() { return TLV::EstimateStructOverhead(kMaxLabelNameLength, kMaxLabelValueLength); }
99115
};
100116

101117
} // namespace DeviceLayer

src/platform/Linux/PlatformManagerImpl.cpp

+4-7
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ void PlatformManagerImpl::WiFIIPChangeListener()
174174

175175
CHIP_ERROR PlatformManagerImpl::_InitChipStack()
176176
{
177-
CHIP_ERROR err;
178177
struct sigaction action;
179178

180179
memset(&action, 0, sizeof(action));
@@ -200,21 +199,19 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack()
200199
#endif
201200

202201
// Initialize the configuration system.
203-
err = Internal::PosixConfig::Init();
204-
SuccessOrExit(err);
202+
ReturnErrorOnFailure(Internal::PosixConfig::Init());
205203
SetConfigurationMgr(&ConfigurationManagerImpl::GetDefaultInstance());
206204
SetDiagnosticDataProvider(&DiagnosticDataProviderImpl::GetDefaultInstance());
207205
SetDeviceInfoProvider(&DeviceInfoProviderImpl::GetDefaultInstance());
206+
ReturnErrorOnFailure(DeviceInfoProviderImpl::GetDefaultInstance().Init());
208207

209208
// Call _InitChipStack() on the generic implementation base class
210209
// to finish the initialization process.
211-
err = Internal::GenericPlatformManagerImpl_POSIX<PlatformManagerImpl>::_InitChipStack();
212-
SuccessOrExit(err);
210+
ReturnErrorOnFailure(Internal::GenericPlatformManagerImpl_POSIX<PlatformManagerImpl>::_InitChipStack());
213211

214212
mStartTime = System::SystemClock().GetMonotonicTimestamp();
215213

216-
exit:
217-
return err;
214+
return CHIP_NO_ERROR;
218215
}
219216

220217
CHIP_ERROR PlatformManagerImpl::_Shutdown()

0 commit comments

Comments
 (0)